139

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

PS1="Blah Blah Blah"

和一些使用

PROMPT_COMMAND="Blah Blah Blah"

在 Bash shell 中设置提示时(有些人同时使用)。两者有什么区别?Stack Overflow 搜索,甚至更广泛的 Google 搜索都没有让我得到结果,因此即使是指向正确位置的链接来寻找答案也将不胜感激。

4

6 回答 6

76

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 $

更新

在阅读了评论和鲍勃的回答后,我认为按照他的描述写它会更好。它比我最初在上面写的更易于维护,其中 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
于 2010-06-17T01:45:47.807 回答
70

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

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

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

于 2010-06-17T01:38:00.433 回答
50

不同之处在于PS1使用的实际提示字符串,并且PROMPT_COMMAND是在提示之前执行的命令。如果你想要最简单、最灵活的方式来构建提示,试试这个:

把它放在你的.bashrc文件中:

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

然后编写一个脚本(Bash、PerlRuby:您的选择),并将其放在文件~/bin/bash_prompt中。

该脚本可以使用它喜欢的任何信息来构建提示。这要简单得多,IMO,因为您不必学习为PS1变量开发的有点巴洛克式的替换语言。

您可能认为您可以通过简单地PROMPT_COMMAND直接设置为~/bin/bash_prompt并设置PS1为空字符串来做同样的事情。

起初这似乎可行,但您很快就会发现 readline 代码希望PS1设置为实际提示,并且当您向后滚动历史记录时,结果会变得一团糟。

此解决方法导致PS1始终反映最新提示(因为该函数设置了PS1调用 shell 实例所使用的实际变量),这使得 readline 和命令历史记录工作正常。

于 2012-06-19T18:57:49.037 回答
12

来自man bash

PROMPT_COMMAND

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

PS1

此参数的值被扩展(参见下面的 PROMPTING)并用作主要提示字符串。默认值为 ''\s-\v\$ ''。

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

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

如果您想在打印提示之前执行其他操作,请使用PROMPT_COMMAND. 例如,如果您想将缓存的写入同步到磁盘,您可以编写:

PROMPT_COMMAND='sync'
于 2014-07-20T04:07:10.903 回答
1

不同之处在于

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

PS1在每个提示符处进行变量扩展和命令替换。没有任何需要使用PROMPT_COMMAND来为任意代码分配值PS1或运行任意代码。您可以轻松地export PS1='$(uuidgen) $RANDOM'在文件中执行一次.bash_profile。只需使用单引号。

于 2018-09-10T17:08:17.223 回答
1

是的,所以要尝试真正确定这一点:

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

我的意思是,如果一个人想在提示符之外设置 另一个作用域的变量:取决于 shell,该变量可能需要首先在外面声明,$PS1或者(最坏的情况)一个人可能不得不对在 FIFO 之前等待的东西感到满意呼叫$PS1(并在结束时再次武装$PS1);这\u \h可能会引起一些麻烦,特别是如果您使用一些花哨的正则表达式;但除此之外:可以PROMPT_COMMAND通过在内部使用命令替换来完成任何事情$PS1(也许在极端情况下,显式子shell)?

对?

于 2019-05-07T07:57:28.963 回答