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:
I do not know how to make this permanent. However, this should definitely give you some pointers.