Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Is there a way to make bash display stderr messages in red color?

share|improve this question
1  
I guess bash will never colorize its output: some program may want to parse something, and colorizing will spoil data with escaped sequences. A GUI app should handle colors, i guess. –  kolypto Aug 26 '09 at 22:20

8 Answers 8

up vote 35 down vote accepted
command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)
share|improve this answer
    
Great! But i wonder if there's a way to make it permanent :) –  kolypto Aug 26 '09 at 21:47
    
#Tync: You would replace 'command' with 'exec', but that will break the prompt, and may also break other commands that use stderr interactively (rm -i, for example). –  Juliano Aug 26 '09 at 22:10
    
thanks for the +1 :) –  Balázs Pozsár Jul 22 '11 at 23:45
2  
Great tip! Suggestion: By adding >&2 right before ; done), the output intended for stderr actually is written to stderr. That's helpful if you want to capture the normal output of the program. –  henko Oct 31 '12 at 8:12
3  
The following uses tput, and is slightly more readable in my opinion: command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done) –  Stefan Lasiewski Feb 14 '13 at 21:59

You can also check out stderred: https://github.com/sickill/stderred

share|improve this answer
    
Wow, this utility is great, the only thing that it would need is to have an apt repository that installs it for all users, with one line, not having to do more work to enable it. –  sorin Apr 3 '12 at 14:17
    
Seemed to work well when I tested it with a build script in a separate terminal, but I'm hesitant to use it globally (in .bashrc). Thanks though! –  Joel Purra Aug 24 '12 at 15:18

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 the stderr of the command to stdout so that it becomes sed's stdin.
  • >&3 — Shorthand for 1>&3, this redirects stdout to a new temporary file descriptor 3. 3 gets routed back into stdout later.
  • sed ... — Because of the redirects above, sed's stdin is the stderr 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
  • & — The sed 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 for 1>&2, this redirects sed's stdout to stderr.
  • 3>&1 — Redirects the temporary file descriptor 3 back into stdout.
share|improve this answer
1  
+1 best answer! absolutly underrated! –  muhqu Sep 20 '13 at 11:27
    
Great answer and even better explanation –  Daniel Serodio Oct 22 at 19:56

I've made a wrapper script that implements Balázs Pozsár's answer in pure bash. Save it in your $PATH and prefix commands to colorize their output.


    #!/bin/bash

    if [ $1 == "--help" ] ; then
        echo "Executes a command and colorizes all errors occured"
        echo "Example: `basename ${0}` wget ..."
        echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
        exit 0
        fi

    # Temp file to catch all errors
    TMP_ERRS=$(mktemp)

    # Execute command
    "$@" 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" | tee --append $TMP_ERRS; done)
    EXIT_CODE=$?

    # Display all errors again
    if [ -s "$TMP_ERRS" ] ; then
        echo -e "\n\n\n\e[01;31m === ERRORS === \e[0m"
        cat $TMP_ERRS
        fi
    rm -f $TMP_ERRS

    # Finish
    exit $EXIT_CODE

share|improve this answer
2  
This could be made more efficient if "|tee..." was put after "done". –  Juliano Aug 27 '09 at 1:27

The bash way of making stderr permanently red is using 'exec' to redirect streams. Add the following to your bashrc:

exec 9>&2
exec 8> >(
    while IFS='' read -r line || [ -n "$line" ]; do
       echo -e "\033[31m${line}\033[0m"
    done
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'

I have posted on this previously: How to set font color for STDOUT and STDERR

share|improve this answer

You can use a function like this


 #!/bin/sh

color() {
      printf '\033[%sm%s\033[m\n' "$@"
      # usage color "31;5" "string"
      # 0 default
      # 5 blink, 1 strong, 4 underlined
      # fg: 31 red,  32 green, 33 yellow, 34 blue, 35 purple, 36 cyan, 37 white
      # bg: 40 black, 41 red, 44 blue, 45 purple
      }
string="Hello world!"
color '31;1' "$string"

share|improve this answer
4  
Not addressing the problem. You haven't provided a way of separating stderr from stdout, which is what the O.P. is interested in. –  Jeremy Visser Aug 27 '09 at 1:54

I have a slightly modified version of O_o Tync's script. I needed to make these mods for OS X Lion and it's not perfect because the script sometimes completes before the wrapped command does. I've added a sleep but I'm sure there's a better way.

#!/bin/bash

   if [ $1 == "--help" ] ; then
       echo "Executes a command and colorizes all errors occured"
       echo "Example: `basename ${0}` wget ..."
       echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
       exit 0
       fi

   # Temp file to catch all errors
   TMP_ERRS=`mktemp /tmp/temperr.XXXXXX` || exit 1

   # Execute command
   "$@" 2> >(while read line; do echo -e "$(tput setaf 1)$line\n" | tee -a $TMP_ERRS; done)
   EXIT_CODE=$?

   sleep 1
   # Display all errors again
   if [ -s "$TMP_ERRS" ] ; then
       echo -e "\n\n\n$(tput setaf 1) === ERRORS === "
       cat $TMP_ERRS
   else
       echo "No errors collected in $TMP_ERRS"
   fi
   rm -f $TMP_ERRS

   # Finish
   exit $EXIT_CODE
share|improve this answer

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.