The issue is here:
PS1='...\[$ALERT_COLOR\]$exit_status ...\$ '
That is a parameter expansion, it doesn't call the function you've set up.
You need to call the function within a command substitution, e.g.
$(exit_status), or from
PROMPT_COMMAND. If you do, take care with the
\[ .. \] escapes: Bash interprets them before other expansions in the prompt, so you have to hardcode them in the prompt string (they can't be parts of variables or other things expanded in the prompt).
And if not expanding the prompt escapes from variables seems backwards to you, I can't blame you. But that's the way it's documented:
In addition, the following table describes the special characters which can appear in the prompt variables
After the string is decoded, it is expanded via parameter expansion, command substitution, [...]
Something like this should work:
if [ "$?" != 0 ]; then
PS1='\[$exit_color\][$?]\[$normal_color\] \w\$ '
I would have thought it'd need a temporary variable to hold the exit status, but apparently
PROMPT_COMMAND doesn't modify the value of
$? that's expanded in the prompt. If call the function with a command substitution from inside the prompt string, then you need a workaround, as the exit code of the command substitution takes effect. Something like this:
if [ "$exit_code" != 0 ]; then
PS1='\[$(exit_color)\][$?]\[$normal_color\] \w\$ '
I would use the version with
PROMPT_COMMAND, just to save the subshell fork caused by the command substitution, but in practice the effect is minimal.