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?
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
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.
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.
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.