PS1和 PROMPT_COMMAND 之间的区别是什么?

在查看 这条超赞的线时,我注意到一些示例使用

PS1="Blah Blah Blah"

还有些用处

PROMPT_COMMAND="Blah Blah Blah"

在 Bash shell 中设置提示符时(有些同时使用两者)。这两者有什么区别?一个 Stack Overflow 搜索,甚至一个更广泛的 Google 搜索都不会给我带来结果,所以即使是一个链接到正确的地方去寻找答案也是不错的。

57088 次浏览

来自 GNU Bash 文档页面(Bash 参考手册) :

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

我从来没有用过它,但是当我只有 的时候我可以用它。

PROMPT _ COMMAND 可以包含普通的 Bash 语句,而 PS1变量也可以包含变量中的特殊字符,比如表示主机名的’h’。

例如,下面是同时使用 PROMPT _ COMMAND 和 PS1的 Bash 提示符。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 $

更新

在阅读了评论和鲍勃的回答之后,我认为按照他的描述来写更好。它比我最初在上面写的更易于维护,PS1变量设置在 PROMPT _ COMMAND 中,后者本身是一个超级复杂的字符串,在运行时由 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

区别在于,PS1是实际使用的提示字符串,而 PROMPT_COMMAND是在提示之前执行的命令。如果你想用最简单、最灵活的方式构建一个提示符,试试下面的方法:

把这个放到你的 。 bashrc文件里:

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

然后编写一个脚本(Bash、 Perl露比: 您自己选择) ,并将其放在文件 ~/bin/bash _ 提示符中。

该脚本可以使用它喜欢的任何信息来构造提示符。这是非常简单的,我的意思是,因为你不必学习有点巴洛克式的替代语言,只是为 PS1变量开发。

您可能认为只需将 PROMPT_COMMAND直接设置为 ~/bin/bash _ 提示符,并将 PS1设置为空字符串即可。

起初,这似乎是有效的,但是您很快就会发现 readline 代码期望将 PS1设置为实际的提示符,当您在历史中向后滚动时,结果就会出现混乱。

这种解决方案使 PS1始终反映最新的提示(因为函数设置了调用 shell 的实例使用的实际 PS1变量) ,这使 readline 和 command history 工作得很好。

来自 man bash:

PROMPT_COMMAND

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

PS1

此参数的值被展开(参见下面的 PROMPING)并用作主提示字符串。默认值是“ s-v $”。

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

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

如果希望在打印提示符之前执行其他操作,请使用 PROMPT_COMMAND。例如,如果要将缓存的写操作同步到磁盘,可以写:

PROMPT_COMMAND='sync'

区别在于

  • 如果您从 PROMPT_COMMAND输出一个不完整的行,它将会打乱您的 Bash 提示符
  • PS1代替 \H和朋友
  • PROMPT_COMMAND运行它的内容,而 PS1使用它的内容作为提示符。

PS1在每个提示符下进行可变展开和指令替代。不需要使用 PROMPT_COMMANDPS1赋值或运行任意代码。你可以很容易地在文件 .bash_profile中做一次 export PS1='$(uuidgen) $RANDOM'。只用单引号。

是啊,所以我们要把这个问题搞清楚:

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

我的意思是,如果一个人想要 准备好了 abC8变量的作用域在提示符之外,根据 shell 的不同,这个变量可能需要首先在 $PS1之外声明,或者(最糟糕的情况)你可能需要在调用 $PS1之前等待一个 FIFO (在 $PS1结束时再次启动) ,\u abC4可能会造成一些麻烦,特别是如果你使用一些花哨的正则表达式,但是否则: 你可以通过在 $PS1内使用指令替代来完成任何 PROMPT_COMMAND可以完成的事情(也许在角落的情况下,显式的 subshell) ?

对吧?