Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a Bash script that is being run interactively and as a cron job. When run interactively it outputs colored text on the terminal. However, when run in cron it doesn't have a terminal and therefore I get plenty of  and similar in the output.

Is there a way in Bash to tell it to swallow the escape codes if the output device doesn't support them?

This is related to How to check if bash can print colors which is about checking the condition. However, I want to change as little as possible in the invocation of echo or printf while retaining the dual functionality of colors or not depending on the output device.

share|improve this question

3 Answers 3

up vote 2 down vote accepted

Not exactly swallowing, but you can remove them with parameter expansion:

str='Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world'

# colorful output
echo -e "$str"

# colorless output    
echo -e "${str//\\e\[+([0-9;])m}"

The above in bash requires the extglob shell option to be turned on. (shopt -s extglob)

To make it easier to use, define a function:

function ecco() { [ -t 1 ] && echo -e "$1" || echo -e "${1//\\e\[+([0-9;])m}"; }

Then you just call it:

ecco 'Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world'

To check that it works, just redirect its output and the colors will disappear:

ecco 'Hello \e[31mc\e[32mo\e[33ml\e[34mo\e[35mr\e[m world' | cat
share|improve this answer
    
That's a very clever idea. Thanks. Accepting. –  0xC0000022L Nov 19 '13 at 20:01
1  
You're missing the part where you determine whether to do the filtering. –  Gilles Nov 20 '13 at 0:15

Check whether you're printing to a terminal. That's what programs such as GNU ls and GNU grep do when you tell them --color=auto.

Even if you're printing to a terminal, in theory, it might not understand the color-changing escape sequences. In practice, all the common and most not-so-common terminals understand these sequences: all the X11 terminal emulators I've ever seen, screen, tmux, the Linux console, the *BSD consoles, PuTTY, rxvt, Console2, ConEmu, …

normal=
green=
…
if [ -t 1 ]; then
  normal=$'\e[0m'
  green=$'\e32m'
  …
 fi
 …
 echo "foobar ${green}OK${normal}"

The test is [ -t 1 ] for standard output and [ -t 2 ] for standard error.

In shells that don't support $'…' expansion, you can generate an escape character portably with esc=$(echo _ | tr _ '\033')

share|improve this answer

you should just check, in your script, if it's being run interactively or not?

http://www.gnu.org/software/bash/manual/html_node/Is-this-Shell-Interactive_003f.html

Quotes:

6.3.2 Is this Shell Interactive?

To determine within a startup script whether or not Bash is running interactively, test the value of the ‘-’ special parameter. It contains i when the shell is interactive. For example:

case "$-" in
  *i*)   echo This shell is interactive ;;
   *)    echo This shell is not interactive ;;
esac

Alternatively, startup scripts may examine the variable PS1; it is unset in non-interactive shells, and set in interactive shells. Thus:

if [ -z "$PS1" ]; then
   echo This shell is not interactive
else
   echo This shell is interactive
fi

and define a set of variables to "_escape_codes_" if it's interactive and to "" if not, and use those variables to colorize the output in the script (in the interactive environment they will have escape codes, in the non-interactive they will add nothing to the text).

ex:

case "$-" in
  *i*)    _bold_="$(printf '\033[1m')"
          _norm_="$(printf '\033[0m')"
          ;;
  *)      _bold_=""
          _norm_=""
          ;;
esac
echo "this ${_bold_}text${_norm_} is important"
share|improve this answer
1  
note that I know the double quotes around my "$(...)" are not needed here, but I prefer to get in the habit when defining variables... and it colorizes "better" (ymmv) in some editors. –  Olivier Dulac Nov 19 '13 at 19:52
1  
Whether the shell is interactive is not the issue here. The script won't be run by an interactive shell, what matters is whether stdout (or stderr as the case may be) is a terminal. –  Gilles Nov 20 '13 at 0:14
    
@Gilles: good thinking. you're right! –  Olivier Dulac Nov 20 '13 at 9:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.