Ubuntu – How to write to stderr so that stderred colours it red

bashcommand lineredirectscripts

For background, I previously asked this question.

I am using stderred to turn stderr text in red when diplayed on a terminal. This works nicely on most occasions, more specifically for what appear to be binary executables as opposed to bash scripts.

I realized that stderred does not appear to work when stderr is referred to directly from a command called from a terminal.

For example, using stderred I still do not have red if I use redirection as with the following:

echo "pomme" 1>&2

How is redirection any different than other cases with regards to the stderred hook?

How can I have red for stderr output if I redirect 1>&2 in a /bin/bash context, as I do in my bash scripts (Ubuntu 15.10)?

Best Answer

  • If you look at stderred's README, you'll note that it modifies the write() function (and associated stream functions):

    stderred hooks on write() and a family of stream functions (fwrite, fprintf, error...) from libc in order to colorize all stderr output that goes to terminal thus making it distinguishable from stdout. Basically it wraps text that goes to file with descriptor "2" with proper ANSI escape codes making text red.

    Emphasis mine.

    When you redirect stdout to stderr, they point to the same thing, true. However, the function calls that wrote to stdout still refer to it as stdout, no matter what redirection you do. They still access file descriptor 1, not 2.

    If you want to write to stderr, and have it coloured, normal shell redirection will not suffice. You'll need to use something that writes directly to stderr. The awk function in the similar Unix & Linux post can be adapted to work with multiple arguments:

    error () (
      IFS=' '
      awk -v msg="$*" 'BEGIN { print msg > "/dev/stderr" }'

    I used /dev/stderr since that's easier to read and mentioned in the GNU awk docs. Also note that I have used ( ) instead of { } for command grouping. This causes the commands to be run in a subshell, so I can safely modify IFS without the calling shell or script being affected.