What is the difference between PS1 and PROMPT_COMMAND

后端 未结 6 1650
栀梦
栀梦 2020-12-07 07:58

While taking a look at this awesome thread I noticed that some examples use

PS1=\"Blah Blah Blah\"

and some use

PROMPT_CO         


        
相关标签:
6条回答
  • 2020-12-07 08:50

    From the GNU Bash doc page: http://www.gnu.org/software/bash/manual/bashref.html

    PROMPT_COMMAND
        If set, the value is interpreted as a command to execute before
        the printing of each primary prompt ($PS1).
    

    I never used it, but I could have used this back when I only had sh.

    0 讨论(0)
  • 2020-12-07 08:51

    the difference is that

    • if you output incomplete line from PROMPT_COMMAND, it will screw your bash prompt
    • PS1 substitutes \H and friends
    • PROMPT_COMMAND runs its contents, PS1 uses its contents as prompt.

    PS1 does variable expansion and command substitution at each prompt, no need to use PROMPT_COMMAND to assign value to PS1 or to run arbitrary code. you can easily do export PS1='$(uuidgen) $RANDOM' once in .bash_profile, just use single quotes

    0 讨论(0)
  • 2020-12-07 08:54

    Yeah, so to try to really nail this down:

    • PROMPT_COMMAND is a handy bash convenience variable/function, but there is, strictly speaking, nothing that cannot also be done using PS1 alone, correct?

    I mean, if one wants to set another variable with scope outside the prompt: depending on the shell, that variable would probably need to be declared first outside $PS1 or (worst case) one might have to get fancy with something waiting on a FIFO prior to calling $PS1 (and armed again at the end of $PS1); the \u \h might cause some trouble, particularly if you're using some fancy regex; but otherwise: one can accomplish anything PROMPT_COMMAND can by using command substitution within $PS1 (and, maybe in corner cases, explicit subshells)?

    Right?

    0 讨论(0)
  • 2020-12-07 08:56

    PROMPT_COMMAND can contain ordinary bash statements whereas the PS1 variable can also contain the special characters, such as '\h' for hostname, in the variable.

    For example here is my bash prompt that uses both PROMPT_COMMAND and PS1. The bash code in PROMPT_COMMAND works out what git branch you might be in and displays that at the prompt, along with the exit status of the last run process, hostname and basename of the pwd. The variable RET stores the return value of the last executed program. This is convenient to see if there was an error and the error code of the last program I ran in the terminal. Note the outer ' surrounding the entire PROMPT_COMMAND expression. It includes PS1 so that this variable is re-evaluated each time the PROMPT_COMMAND variable is evaluated.

    PROMPT_COMMAND='RET=$?;\
      BRANCH="";\
      ERRMSG="";\
      if [[ $RET != 0 ]]; then\
        ERRMSG=" $RET";\
      fi;\
      if git branch &>/dev/null; then\
        BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2);\
      fi;
    PS1="$GREEN\u@\h $BLUE\W $CYAN$BRANCH$RED$ERRMSG \$ $LIGHT_GRAY";'
    

    Example output looks like this in a non-git directory:

    sashan@dhcp-au-122 Documents  $ false
    sashan@dhcp-au-122 Documents  1 $ 
    

    and in a git directory you see the branch name:

    sashan@dhcp-au-122 rework mybranch $ 
    

    Update

    After reading the comments and Bob's answer I think that writing it as he describes is better. It's more maintainable than what I originally wrote above, where the PS1 variable is set inside the PROMPT_COMMAND, which itself is a super complicated string that is evaluated at runtime by bash. It works, but it's more complicated than it needs to be. To be fair I wrote that PROMPT_COMMAND for myself about 10 years ago and it worked and didn't think too much about it.

    For those curious as to how I've amended my things, I've basically put the code for the PROMPT_COMMAND in separate file (as Bob described) and then echo the string that I intend to be PS1:

    GREEN="\[\033[0;32m\]"
    CYAN="\[\033[0;36m\]"
    RED="\[\033[0;31m\]"
    PURPLE="\[\033[0;35m\]"
    BROWN="\[\033[0;33m\]"
    LIGHT_GRAY="\[\033[0;37m\]"
    LIGHT_BLUE="\[\033[1;34m\]"
    LIGHT_GREEN="\[\033[1;32m\]"
    LIGHT_CYAN="\[\033[1;36m\]"
    LIGHT_RED="\[\033[1;31m\]"
    LIGHT_PURPLE="\[\033[1;35m\]"
    YELLOW="\[\033[1;33m\]"
    WHITE="\[\033[1;37m\]"
    RESTORE="\[\033[0m\]" #0m restores to the terminal's default colour
    
    if [ -z $SCHROOT_CHROOT_NAME ]; then
        SCHROOT_CHROOT_NAME=" "
    fi
    BRANCH=""
    ERRMSG=""
    RET=$1
    if [[ $RET != 0 ]]; then
        ERRMSG=" $RET"
    fi
    if which git &>/dev/null; then
        BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2)
    else
        BRANCH="(git not installed)"
    fi
    echo "${GREEN}\u@\h${SCHROOT_CHROOT_NAME}${BLUE}\w \
    ${CYAN}${BRANCH}${RED}${ERRMSG} \$ $RESTORE"
    

    and in my .bashrc

    function prompt_command {
        RET=$?
        export PS1=$(~/.bash_prompt_command $RET)
    }
    PROMPT_DIRTRIM=3
    export PROMPT_COMMAND=prompt_command
    
    0 讨论(0)
  • 2020-12-07 08:56

    From man bash:

    PROMPT_COMMAND

    If set, the value is executed as a command prior to issuing each primary prompt.

    PS1

    The value of this parameter is expanded (see PROMPTING below) and used as the primary prompt string. The default value is ''\s-\v\$ ''.

    If you simply want to set the prompt string, using PS1 alone is enough:

    PS1='user \u on host \h$ '
    

    If you want to do something else just before printing the prompt, use PROMPT_COMMAND. For example, if you want to sync cached writes to disk, you can write:

    PROMPT_COMMAND='sync'
    
    0 讨论(0)
  • 2020-12-07 08:58

    The difference is that PS1 is the actual prompt string used, and PROMPT_COMMAND is a command that is executed just before the prompt. If you want the simplest, most flexible way of building a prompt, try this:

    Put this in your .bashrc:

    function prompt_command {
      export PS1=$(~/bin/bash_prompt)
    }
    export PROMPT_COMMAND=prompt_command
    

    Then write a script (bash, perl, ruby: your choice), and place it in ~/bin/bash_prompt.

    The script can use any information it likes to construct a prompt. This is much simpler IMO because you don't have to learn the somewhat baroque substitution language that was developed just for the PS1 variable.

    You might think that you could do the same by simply setting PROMPT_COMMAND directly to ~/bin/bash_prompt, and setting PS1 to the empty string. This at first appears to work, but you soon discover that the readline code expects PS1 to be set to the actual prompt, and when you scroll backwords in history, things get messed up as a result. This workaround causes PS1 to always reflect the latest prompt (since the function sets the actual PS1 used by the invoking instance of the shell), and this makes readline and command history work fine.

    0 讨论(0)
提交回复
热议问题