Is it even achievable?
I would like the output from a command’s stderr to be rendered in a different color than stdout (for example, in red).
I need such a modification to work with the Bash shell in the Konsole, XTerm, or GNOME Terminal terminal emulators on Linux.
Advertisement
Answer
Here’s a solution that combines some of the good ideas already presented.
Create a function in a bash script:
color() ( set -o pipefail; "$@" 2>&1>&3 | sed $'s,.*,e[31m&e[m,' >&2 ) 3>&1
Use it like this:
$ color command -program -args
It will show the command’s stderr
in red.
Keep reading for an explanation of how it works. There are some interesting features demonstrated by this command.
color()...
— Creates a bash function called color.set -o pipefail
— This is a shell option that preserves the error return code of a command whose output is piped into another command. This is done in a subshell, which is created by the parentheses, so as not to change the pipefail option in the outer shell."$@"
— Executes the arguments to the function as a new command."$@"
is equivalent to"$1" "$2" ...
2>&1
— Redirects thestderr
of the command tostdout
so that it becomessed
‘sstdin
.>&3
— Shorthand for1>&3
, this redirectsstdout
to a new temporary file descriptor3
.3
gets routed back intostdout
later.sed ...
— Because of the redirects above,sed
‘sstdin
is thestderr
of the executed command. Its function is to surround each line with color codes.$'...'
A bash construct that causes it to understand backslash-escaped characters.*
— Matches the entire line.e[31m
— The ANSI escape sequence that causes the following characters to be red&
— Thesed
replace character that expands to the entire matched string (the entire line in this case).e[m
— The ANSI escape sequence that resets the color.>&2
— Shorthand for1>&2
, this redirectssed
‘sstdout
tostderr
.3>&1
— Redirects the temporary file descriptor3
back intostdout
.
Here’s an extension of the same concept that also makes STDOUT green:
function stdred() ( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,e[31m&e[m,' >&2 ) 3>&1 | sed $'s,.*,e[32m&e[m,' )