Is it possible to pre-evaluate a value in bash's PS1?

I’m trying to build a Bash prompt which will have both my git branch information (using __git_ps1 from git’s bash-completion) and a little colored smiley to indicate whether the most recently run command was successful.

The smiley is created using this technique, which I found here on SO:

  • How to capture a git commit message and run an action
  • How to check if Git is installed from .bashrc
  • setgid bit not preserved by git on new directory in `.git` folder?
  • Bash - get last dirname/filename in a file path argument
  • Run git gc on multiple repositories
  • Delete multiple remote branches in git
  • SMILEY="${GREEN}:)${COLOR_NONE}"
    FROWNY="${RED}:(${COLOR_NONE}"
    STATUS_EMOTICON="if [ \$? = 0 ]; then echo \"${SMILEY}\"; else echo \"${FROWNY}\"; fi"
    

    Here’s the prompt line I want to use:

    export PS1="[\t]${RED}[\u@$MACHINE:${BOLD_CYAN}\w${GREEN}\$(__git_ps1 ' %s')${RED}]${COLOR_NONE} \`${STATUS_EMOTICON}\`\n$ "
    

    Unfortunately, it looks like the programs that are run by __git_ps1 override the $? value, and I end up with every emoticon being a green smiley, even after running false.

    Taking out the __git_ps1 call…

    export PS1="[\t]${RED}[\u@$MACHINE:${BOLD_CYAN}\w${RED}]${COLOR_NONE} \`${STATUS_EMOTICON}\`\n$ "
    

    …makes the emoticon work correctly.

    So what I apparently need to do is evaluate ${STATUS_EMOTICON} before running __git_ps1, but include the evaluated value after __git_ps1‘s output. Is that possible?

  • How does SHA generate unique codes for big files in git
  • git init template, replacing modified hooks
  • Best Practice for Adding .gitignore to Repo
  • What's the workflow to contribute to an open source project using git pull requests? (eg. via Github)
  • Git Push - Username and password in the remote url
  • npm package from private github repo, install vs update (package.json)
  • One Solution collect form web for “Is it possible to pre-evaluate a value in bash's PS1?”

    Don’t put $(cmd) or `cmd` directly in your PS1. Instead, use Bash’s PROMPT_COMMAND var. What I usually do is define a function _PS1_cmd and set PROMPT_COMMAND=_PS1_cmd. Then in _PS1_cmd, I set misc vars I’d like to include in PS1. For example:

    THE-OLD-PROMPT # cat prompt.rc
    function _PS1_cmd()
    {
        local saveExit=$?
    
        # This non-zero exit will not affect $? on command line
        g_git_ps1=$( echo TESTING; exit 1 )
        if (( saveExit )); then
            g_smiley=':('
        else
            g_smiley=':)'
        fi
    
        # Seems like this is not necessary, at least with bash 4.2.37. But
        # to be safe, always return it.
        return $saveExit
    }
    
    PROMPT_COMMAND=_PS1_cmd
    PS1='$g_git_ps1 $g_smiley '
    THE-OLD-PROMPT # source ./prompt.rc
    TESTING :) ( exit 123 )
    TESTING :( echo $?
    123
    TESTING :) echo $?
    0
    TESTING :)
    
    Git Baby is a git and github fan, let's start git clone.