I have the following function to colorize the stderr output of a command:

red=`tput setaf 1`

colorerr() {
  (trap 'tput sgr0' EXIT; eval "$* 2> >(echo -n \"${red}\"; cat -;)")


colorerr "bash -c 'cd ${WEB_APP_DIR}; npm run-script build'"

The script uses set -e, trap ... ERR, and trap ... EXIT to report line numbers and stack traces on failures. Everything is working fine, except if the command string passed into colorerr fails, I wanted to catch the error and give better reporting (since telling me that a failure happend in the colorerr function isn't useful).

I tried the standard || ... construction, but the error from the subshell within colorerr was still triggering the ERR trap. As a test, I tried the following:

(trap 'tput sgr0' EXIT; eval "$* 2> >(echo -n \"${red}\"; cat -;)") ||

But the ERR trap is still triggered. Why isn't the || true setting the error code to '0' as it normally does?

  • 2
    the ||true is outside of the subshell, and the subshell inherits traps (bash reference - 3.7.3 Command Execution Environment) "The shell has an execution environment, which consists of the following: ...current traps set by trap..." – Jeff Schaller Sep 7 '18 at 14:49
  • Thanks; that would make sense. I had thought traps were not inherited by subshells based on this: unix.stackexchange.com/questions/282722/… – zanerock Sep 7 '18 at 15:18
  • 2
    Interesting! I commented instead of answering, since I can't test right now; just passing along what the doc says. Ahh! I may be on the wrong track. "A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately" ... you may be seeing that. – Jeff Schaller Sep 7 '18 at 15:33
  • Please show the code that sets the value of the ${red} variable. – agc Sep 10 '18 at 8:07

Not really an answer, but a workaround. Try this:

col-err() { "$@" 2> >(grep --color .) ; }

The syntax is slightly different than the colorerr function in the question. For col-err, do not quote the command to be run:

col-err bash -c 'cd ${WEB_APP_DIR}; npm run-script build'

Example that can be run anywhere:

col-err bash -c 'ls    $SHELL ${SHELL}_no_such ; echo
                 ls -l $HOME   ${HOME}_no_such | head -2'

Since col-err calls grep, it works with the $GREP_COLORS variable. To change the color to green (the first ms=01;32 below) for just one use:

GREP_COLORS='ms=01;32:mc=01;33:sl=:cx=:fn=35:ln=32:bn=32:se=36' \
col-err bash -c 'ls    $SHELL ${SHELL}_no_such ; echo
                 ls -l $HOME   ${HOME}_no_such | head -2'

Note: color string adapted from Chriki's answer to "Use different colors for every other grep".

  • I ended up trying a few different variations of the colorerr function. The current iteration is: (eval "$@" 2>&1>&3|sed 's/^\(.*\)$/'$'\e''[31m\1'$'\e''[m/'>&2)3>&1, and with proper calling convention, it's working for me. I might give your suggestion a try since the setup is much easier than the complicated redirection I'm currently using. – zanerock Sep 18 '18 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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