views:

876

answers:

4

I'm writing a shell script that uses ANSI color characters on the command line.

Example: example.sh

#!/bin/tcsh
printf "\033[31m Success Color is awesome!\033[0m"

My problem is when doing:

$ ./example.sh > out

or

$./example.sh | grep

The ASCII codes will be sent out raw along with the text, mucking up the output and just generally causing chaos.

I'm interested to know if there is a way to detect this so I could disable color for this special case.

I've search the tcsh man pages and the web for a while and have not been able to find anything shell specific yet.

I'm not bound to tcsh, it's our group standard... but who cares?

Is it possible to detect, inside a shell script, if your output is being redirected or piped?

A: 

As far as I know, there is no way to determine the final destination of the output of your shell script; the only thing you can do is provide a switch which allows for suppression of control characters in the output.

McWafflestix
+5  A: 

Inside a bourne shell script (sh, bask, ksh, ...), you can feed the standard output to the tty program (standard in Unix) which tells you whether its input is a tty or not, by using the -s flag.

Put the following into "check-tty":

    #! /bin/sh
    if tty -s <&1; then
      echo "Output is a tty"
    else
      echo "Output is not a tty"
    fi

And try it:

    % ./check-tty
    Output is a tty
    % ./check-tty | cat
    Output is not a tty

I don't use tcsh, but there must be a way to redirect your standard output to tty's standard input. If not, use

    sh -c "tty -s <&1"

as your test command in your tcsh script, check its exit status and you're done.

Samuel Tardieu
Brian Gianforcaro
No it won't (and I just tested it).
Samuel Tardieu
+3  A: 

See this previous SO question, which covers bash. Tcsh provides the same functionality with filetest -t 1 to see if standard output is a terminal. If it is, then print the color stuff, else leave it out. Here's tcsh:

#!/bin/tcsh
if ( -t 1 ) then
        printf "\033[31m Success Color is awesome!\033[0m"
else
        printf "Plain Text is awesome!"
endif
dwc
Didn't work until you edited it. Thanks, this worked great.
Brian Gianforcaro
csh isn't my native language. sorry for the initial goof
dwc
+1  A: 

The detection of the output stream type is covered in the question detect if shell script is running through a pipe.

Having decided that you are talking to terminal, then you can use tput to retrieve the correct escape codes for the particular terminal you are using - this will make the code more portable.

An example script (in bash I am afraid, as tcsh is not my forte) is given below.

#!/bin/bash

fg_red=
fg_green=
fg_yellow=
fg_blue=
fg_magenta=
fg_cyan=
fg_white=
bold=
reverse=
attr_end=

if [ -t 1 ]; then
    fg_red=$(tput setaf 1)
    fg_green=$(tput setaf 2)
    fg_yellow=$(tput setaf 3)
    fg_blue=$(tput setaf 4)
    fg_magenta=$(tput setaf 5)
    fg_cyan=$(tput setaf 6)
    fg_white=$(tput setaf 7)
    bold=$(tput bold)
    reverse=$(tput rev)
    underline=$(tput smul)
    attr_end=$(tput sgr0)
fi

echo "This is ${fg_red}red${attr_end}"
echo "This is ${fg_green}green${attr_end}"
echo "This is ${fg_yellow}yellow${attr_end}"
echo "This is ${fg_blue}blue${attr_end}"
echo "This is ${fg_magenta}magenta${attr_end}"
echo "This is ${fg_cyan}cyan${attr_end}"
echo "This is ${fg_white}white${attr_end}"
echo "This is ${bold}bold${attr_end}"
echo "This is ${reverse}reverse${attr_end}"
echo "This is ${underline}underline${attr_end}"

For more information see "man tput" and "man terminfo" - there are all sorts of escape codes to play with.

Beano