How can I customize the color of error messages in Bash?

Is it possible to customize the Bash error messages attributes?

For example, is it possible to edit the .bash_profile to get the following Bash error message

-bash: cd: foo: No such file or directory

in red?


Sadly, there is no PS prompt variable to control how bash errors are presented.

stderred is a comprehensive solution for this type of problem, but it will not work without modification as it has a hard-coded exclude for bash (read on for good reasons why). Also it's somewhat intrusive (DLL injection).

hilite requires you to use it as a wrapper, this won't work for bash builtin commands like cd.

Your question asks specifically about bash error messages, these are send to stderr, but stderr is also shared with any child processes, i.e. any other commands. I'm not sure if you want to distinguish the two.

A hidden issue here is that bash itself writes the prompt and your input (echo) to stderr. To prove:

bash              # start a sacrificial shell
exec 2> tmpfile   # change stderr to a file
ls                # you will see no prompt, and no command echo
... 
exit              # quit sacrificial shell
cat tmpfile       # contains PS1 prompt, your commands (and any errors too)

Builtins call (or at least should call) the builtin_error() internal function to print errors, this unconditionally calls fprintf() to stderr, so the options are few.

Without jumping through hoops, or patching bash, a simple way of highlighting errors is:

function _t_debug() 
{
    if [ "${BASH_COMMAND:0:6}" != "_t_err" ]; then
        _lastcmd="$BASH_COMMAND"
    fi  
}
function _t_err() 
{
    local rc=$1 nn _type _argv
    #shift; pipe=($*)
    #if [ ${#pipe[*]} -gt 1 ]; then
    #    for ((nn=1; nn<=${#pipe[*]};nn++));do
    #        rc=${pipe[$((nn-1))]}
    #        echo -n "[$nn]=$rc ";
    #        ((rc >=128)) && echo -n "($((rc-128))) "
    #    done
    #fi

    read -a _argv <<< ${_lastcmd}
    _type=$(type -t "${_argv[0]}")

    if [ -n "$_lastcmd" ]; then
        tput setf 4
        printf 'Error %s: "%s"' "${_type}" "${_lastcmd:-unknown command}"
        tput sgr 0
        printf "\n"
    fi

    ((rc >=128)) && echo "[rc=$rc ($((rc-128)))]" ||
    echo "[rc=$rc]"
}
trap '_t_err $? ${PIPESTATUS[*]}' ERR
trap '_t_debug' DEBUG

This uses the bash DEBUG trap to cache each command line before execution, and the ERR trap to output the return codes if non-zero. This won't though for certain bash builtins (specifically compound commands: while/case/for/if and more, see man page).

I use a variation on this in my .profile, though I use the pipe[]/PIPESTATUS[] bit commented out above, it's not compatible with a DEBUG trap as presented above. If you comment out the trap DEBUG then you can use it to show the return code of each command in a pipeline.

(Also, since it's referenced, the command_not_found function hook is bash-4.0+.)


You might want to check out stderrred for a more permanent sollution.


Below solution works for what you want:

# whatever_command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)

Basically, above command prints stderr in red.

Check below screen shot:

enter image description here

I do not know how to make this permanent. However, this should definitely give you some pointers.