Getting a dynamic bash prompt PS1 right

bash, ps1

Solution

Use \x01 (or \001) and \x02 (or \002) and then evaluate them with echo -e:

    function __get_foo_version () {
      FOOVER=$(grep FOOVER $CONF | awk '{print $3}')
      if [[ "$FOOVER" =~ v2$ ]]; then
        #style_foover="${BOLD}${YELLOW}$FOOVER"
>>>     style_foover="\x01${BOLD}${YELLOW}\x02$FOOVER"
      elif [[ "$FOOVER" =~ v1$ ]]; then
        #style_foover="${BOLD}${GREEN}$FOOVER"
>>>     style_foover="\x01${BOLD}${GREEN}\x02$FOOVER"
      fi
>>>   echo -e "$style_foover"
    }

A more complete answer as to why this fixes it is here: https://superuser.com/questions/301353/escape-non-printing-characters-in-a-function-for-a-bash-prompt

Problem

I'm working on a dynamic bash prompt where I want reported in PS1 which version of a config file is enabled on the local filesystem. This is a contrived example of what I'm trying to do, simplified. The things that are going wrong: bad wrapping and/or escape brackets appearing. Can anyone spot what I'm doing wrong? If the contrived config matches "v2", I want to see that version in PS1 as YELLOW. If it's "v1", in the prompt as GREEN. The setup: ``` $ grep FOOVER foo-*.conf foo-v1.conf:# FOOVER xyz-v1 foo-v2.conf:# FOOVER zet-v2 ``` I'd then symlink foo.conf foo-v1.conf. My bashrc: ``` 0 GREEN=$(tput setaf 034) 1 YELLOW=$(tput setaf 3) 2 BLUE=$(tput setaf 4) 3 CYAN=$(tput setaf 6) 4 BOLD=$(tput bold) 5 RESET=$(tput sgr0) 6 CONF=$HOME/foo.conf 7 8 function __get_foo_version () { 9 FOOVER=$(grep FOOVER $CONF | awk '{print $3}') 10 if [[ "$FOOVER" =~ v2$ ]]; then 11 style_foover="${BOLD}${YELLOW}$FOOVER" 12 #style_foover="\[${BOLD}${YELLOW}\]$FOOVER" 13 elif [[ "$FOOVER" =~ v1$ ]]; then 14 style_foover="${BOLD}${GREEN}$FOOVER" 15 #style_foover="\[${BOLD}${GREEN}\]$FOOVER" 16 fi 17 echo $style_foover 18 } 19 20 style_host="\[${RESET}${BLUE}\]" 21 style_path="\[${RESET}${CYAN}\]" 22 style_reset="\[${RESET}\]" 23 24 PS1='user@' 25 PS1+="${style_host}host" 26 PS1+="${style_reset} " 27 PS1+="\$(__get_foo_version) " 28 PS1+="${style_reset}" 29 PS1+="${style_path}\W" 30 PS1+="${style_reset} $ " ``` When I run the above, I get this behavior, which looks good at first: https://i.stack.imgur.com/7cGWf.jpg But when I up-arrow to a long command, the bad wrapping happens: https://i.stack.imgur.com/6sdSq.jpg When I disable lines 11, 14 and enable lines 12, 15, I get the brackets that are intended to handle non-printing chars showing up in PS1: (not enough reputation points to post more than 2 links :( imgur.com slash nkXFDyJ) ``` user@host \[\]xyz-v1 ~ $ ``` .. and I still get the bad wrapping in this case.

Original source