PS1和PROMPT_COMMAND有什么区别


108

在看这个很棒的线程时,我注意到一些示例使用

PS1="Blah Blah Blah"

和一些用途

PROMPT_COMMAND="Blah Blah Blah"

(有些同时使用)在bash shell中设置提示时。两者有什么区别?SO搜索,甚至更广泛的google搜索都无法获得我的结果,因此,即使是指向正确位置以寻找答案的链接也将不胜感激。

Answers:



67

PROMPT_COMMAND可以包含普通的bash语句,而PS1变量也可以在变量中包含特殊字符,例如主机名'\ h'。

例如,这是我的bash提示符,它同时使用PROMPT_COMMAND和PS1。PROMPT_COMMAND中的bash代码可以算出您可能所在的git分支,并在提示符下显示该分支,以及最后运行的进程的退出状态,pwd的主机名和基本名。变量RET存储最后执行的程序的返回值。方便查看是否有错误以及我在终端中运行的最后一个程序的错误代码。注意整个PROMPT_COMMAND表达式的外部'。它包括PS1,以便每次评估PROMPT_COMMAND变量时都重新评估此变量。

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";'

在非git目录中,示例输出如下所示:

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

在git目录中,您会看到分支名称:

sashan@dhcp-au-122 rework mybranch $ 

更新资料

阅读评论和Bob的回答后,我认为按照他的描述进行写作会更好。它比我上面最初写的内容更易于维护,在PS1变量中的PROMPT_COMMAND中设置了PS1变量,它本身是一个超级复杂的字符串,在运行时由bash评估。它可以工作,但是比需要的要复杂得多。公平地说,大约10年前,我为自己写了PROMPT_COMMAND,它起作用了,并且对此考虑得并不多。

对于那些对我如何修改自己的东西感到好奇的人,我基本上将PROMPT_COMMAND的代码放在单独的文件中(如Bob所述),然后回显我打算成为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"

在我的.bashrc中

function prompt_command {
    RET=$?
    export PS1=$(~/.bash_prompt_command $RET)
}
PROMPT_DIRTRIM=3
export PROMPT_COMMAND=prompt_command

1
您可以缩短其中的一行:if git branch &>/dev/null ; then\ 。它将stdout和stderr都重定向到/ dev / null。tldp.org/LDP/abs/html/io-redirection.html

3
无需出口 PROMPT_COMMAND
dolmen's

2
我认为ceving的评论对于此答案也非常正确:Don't set PS1 in PROMPT_COMMAND! Set variables in PROMPT_COMMAND and use them in PS1
phil294

2
我看不出原因,为什么PS1在内部PROMPT_COMMAND进行在线更改是不利的。这是完美的有用代码。与Bob的回答相反,该PS1变量的构造正确。这将根据您的实际情况提供更为复杂的bash提示。
Christian Wolf

2
PS1内部的@ChristianWolf结构PROMPT_COMMAND没有任何作用。这是一个如何不做的例子。在中构造PS1一次.bash_profile,只需使用单引号而不是双引号,以便在每次提示时评估变量替换。
好朋友

46

区别在于PS1是实际使用的提示字符串,而PROMPT_COMMAND是仅在提示之前执行的命令。如果您想要最简单,最灵活的方式来构建提示,请尝试以下操作:

将其放在您的.bashrc中:

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

然后编写一个脚本(bash,perl,ruby:您的选择),并将其放在〜/ bin / bash_prompt中。

该脚本可以使用其喜欢的任何信息来构造提示。这比IMO简单得多,因为您不必学习专门为PS1变量开发的巴洛克式替代语言。

您可能认为可以通过将PROMPT_COMMAND直接设置为〜/ bin / bash_prompt并将PS1设置为空字符串来完成相同的操作。乍一看,这似乎可行,但是您很快就会发现,readline代码希望将PS1设置为实际的提示,并且当您滚动历史记录中的后退单词时,事情就会变得混乱。这种解决方法使PS1始终反映最新的提示(因为该函数设置了由外壳程序的调用实例使用的实际PS1),这使readline和命令历史记录可以正常工作。


17
不要PS1进去PROMPT_COMMAND!在中设置变量PROMPT_COMMAND并在中使用它们PS1。否则,您将失去使用PS1转义序列(如\u或)的功能\h。您必须重新发明它们PROMPT_COMMAND。这可能是可行的,但不可能解决丢失\[\]标记不可打印字符的开始和结束的问题。这意味着您不能在不使终端混淆提示长度的情况下使用颜色。这readline在编辑产生两行的命令时会造成混淆。最终,您的屏幕上一片混乱。
2015年

1
@ceving真的!您可以使用PROMPT_COMMAND更改PS1 的格式并获得两全其美的
体验

3
PROMPT_COMMAND在打印之前执行PS1。我看不到PS1从内部进行设置的问题PROMPT_COMMAND,因为PROMPT_COMMAND完成后,shell将进行打印(PS1PROMPT_COMMAND(或在这种情况下,内部prompt_command)进行了修改)?
费利佩·阿尔瓦雷斯

3
警告:通常不应使用PROMPT_COMMAND将字符直接打印到提示中。Bash不会计算PS1外部打印的字符,这将导致它错误地放置光标并清除字符。使用PROMPT_COMMAND设置PS1或查看嵌入命令。(Arch Wiki来源
影响

3
我不明白为什么每个人都尝试在PROMPT_COMMAND中做一些技巧而不是仅在PS1 export PS1='$(~/bin/bash_prompt)'中使用命令替换会导致相同的错误看起来很健全
pal

10

来自man bash

PROMPT_COMMAND

如果设置,则在发出每个主要提示之前,将值作为命令执行。

PS1

此参数的值被展开(请参阅下面的PROMPTING),并用作主要提示字符串。默认值为“ \ s- \ v \ $”。

如果您只想设置提示字符串,则PS1单独使用就足够了:

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

如果要在打印提示之前做其他事情,请使用PROMPT_COMMAND。例如,如果要将缓存的写入同步到磁盘,则可以写入:

PROMPT_COMMAND='sync'

1
还可以设置从终端的标题PS1,而不需要PROMPT_COMMAND,作为设置标题的序列可以包括在PS1包裹\[\]
支石墓

1
@dolmen好吧。然后让我们做其他事情,例如动态设置环境变量。
赛尔(Cyker)'16

@Cyker您可以在中动态设置环境变量PS1,它将仅在subshel​​l中进行设置,因此您无法获取其值。但您的例子微不足道PS1='$(sync)user \u on host \h$ '
朋友

1

不同的是

  • 如果您从中输出不完整的行PROMPT_COMMAND,它将破坏您的bash提示
  • PS1替代品\H和朋友
  • PROMPT_COMMAND运行其内容,PS1使用其内容作为提示。

PS1在每次提示时执行变量扩展和命令替换,无需使用PROMPT_COMMAND来为它分配值PS1或运行任意代码。您可以轻松完成export PS1='$(uuidgen) $RANDOM'一次操作.bash_profile,只需使用单引号


0

是的,因此要尝试真正确定这一点:

  • PROMPT_COMMAND是方便的bash便利变量/函数,但是严格来说,没有什么不能PS1单独使用完成的,对吗?

我的意思是,如果要在提示之外设置 具有范围的另一个变量:根据外壳,可能需要首先在外部声明该变量,$PS1或者(最坏的情况)可能要花一些时间在FIFO之前等待呼叫$PS1(并在末尾再次武装$PS1);这\u \h可能会造成一些麻烦,特别是如果您使用一些精美的正则表达式;但是否则:PROMPT_COMMAND通过使用命令替换可以完成任何事情$PS1(或者在某些情况下,使用显式子外壳),吗?

对?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.