Bash – Combine 2 prompts into one, showing error condition in red/orange

bashprompt

As everyone, I have a customized prompt. Mine turns red for root and is green for a normal user and a few other small things:

In bash.bashrc:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\n\$ '

In .bashrc:

PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"

resulting in:

\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\n\$

for a normal user…

That is about the maximum of my abilities with prompts, but a really high-level admin has shared his/her/its prompt with me:

PS1_Error="\[\033[31;1m\]"
PS1_Normal="\[\033[0m\]"
PS1_Inside='${debian_chroot:+($debian_chroot)}\u@\h:\w$bad\$ '
PS1="\`
        retcode=\$? ;
        if [ 0 -ne \$retcode ]; then
                bad=\" [\\\\\\\$?=\$retcode]\"
                echo \"$PS1_Error$PS1_Inside$PS1_Normal\"
        else
                bad='';
                echo \"$PS1_Inside\";
        fi;
\`"
unset PS1_Error PS1_Normal PS1_Inside

which has the fantastic ability to turn red with an error and shows the error number!

As I'm too dumb to even understand how that works (needed variables are unset???), I'm definitely too dumb to incorporate that one into mine (and I would like orange for an error condition…)

As the high-level admin is a really busy guy/girl/neuter, I'm asking on U&L if there is anyone here who understands the above and wants to teach me how to fish instead of giving me a fish? help me incorporate the nice PS1 into the dumb one and explain a bit what's happening here?

Best Answer

These variables describe the prompt itself:

PS1_Error="\[\033[31;1m\]"
PS1_Normal="\[\033[0m\]"
PS1_Inside='${debian_chroot:+($debian_chroot)}\u@\h:\w$bad\$ '

The colors are done using ANSI escape codes. \033 is the escape character (33 = 27 octal), then [31;1m sets text color 31 and effect 1. [0m sets effect 0, i.e. all default. Note how PS1_Inside is in single quotes (''), this means variable substitution is not performed at this step. (It will happen later.)

The real magic happens here:

PS1="\`
         ...
\`"

This sets PS1 to the output of executing the code within the `` characters. Variable expansion will happen to whatever comes out. The code will run every time the prompt is shown. The code itself runs like so:

        retcode=\$? ;

$? contains the result of the previous command. Zero means OK, anything else is a fail condition. This is stored in retcode for the time being. Everything needs to be escaped, because we want variables to be accessed when the code runs, not substituted at the time of definition.

        if [ 0 -ne \$retcode ]; then

If it is not zero, something went wrong. So we echo the prompt style used for errors. bad is used in PS1_Inside above. PS1_Error is used to change the color, PS1_Normal is used to change the color back to normal.

                bad=\" [\\\\\\\$?=\$retcode]\"
                echo \"$PS1_Error$PS1_Inside$PS1_Normal\"
        else

In this case, no error occurred, so we don't do any colors and just output PS1_Inside. bad is set to empty, so nothing will show up in the prompt.

                bad='';
                echo \"$PS1_Inside\";
        fi;

Finally, the helper variables are unset so as not to clutter up the environment.

unset PS1_Error PS1_Normal PS1_Inside
Related Question