Search code examples
bashps1

Simplifying advanced Bash prompt variable (PS1) code


So I've found the following cool Bash prompt:

Bash prompt

..with the very basic logic of:

PS1="\[\033[01;37m\]\$? \$(if [[ \$? == 0 ]]; then echo \"\[\033[01;32m\]\342\234\223\"; else echo \"\[\033[01;31m\]\342\234\227\"; fi) $(if [[ ${EUID} == 0 ]]; then echo '\[\033[01;31m\]\h'; else echo '\[\033[01;32m\]\u@\h'; fi)\[\033[01;34m\] \w \$\[\033[00m\] "

However, this is not very basic and happens to be an incredible mess. I'd like to make it more readable.

How?


Solution

  • Use PROMPT_COMMAND to build the value up in a sane fashion. This saves a lot of quoting and makes the text much more readable. Note that you can use \e instead of \033 to represent the escape character inside a prompt.

    set_prompt () {
        local last_command=$?  # Must come first!
        PS1=""
        # Add a bright white exit status for the last command
        PS1+='\[\e[01;37m\]$? '
        # If it was successful, print a green check mark. Otherwise, print
        # a red X.
        if [[ $last_command == 0 ]]; then
            PS1+='\[\e[01;32m\]\342\234\223 '
        else
            PS1+='\[\e[01;31m\]\342\234\227 '
        fi
        # If root, just print the host in red. Otherwise, print the current user
        # and host in green.
        # in 
        if [[ $EUID == 0 ]]; then
            PS1+='\[\e[01;31m\]\h '
        else
            PS1+='\[\e[01;32m\]\u@\h '
        fi
        # Print the working directory and prompt marker in blue, and reset
        # the text color to the default.
        PS1+='\[\e[01;34m\] \w \$\[\e[00m\] '
    }
    PROMPT_COMMAND='set_prompt'
    

    You can define variables for the more esoteric escape sequences, at the cost of needing some extra escapes inside the double quotes, to accommodate parameter expansion.

    set_prompt () {
        local last_command=$? # Must come first!
        PS1=""
        local blue='\[\e[01;34m\]'
        local white='\[\e[01;37m\]'
        local red='\[\e[01;31m\]'
        local green='\[\e[01;32m\]'
        local reset='\[\e[00m\]'
        local fancyX='\342\234\227'
        local checkmark='\342\234\223'
    
        PS1+="$white\$? "
        if [[ $last_command == 0 ]]; then
            PS1+="$green$checkmark "
        else
            PS1+="$red$fancyX "
        fi
        if [[ $EUID == 0 ]]; then
            PS1+="$red\\h "
        else
            PS1+="$green\\u@\\h "
        fi
        PS1+="$blue\\w \\\$$reset "
    }