Bash:在提示中显示退出状态:

Bash:在提示中显示退出状态:
GREEN="\e[1;32m"
RED="\e[1;31m"
NONE="\e[m"

get_exit_status(){
   es=$?
   if [ $es -eq 0 ]
   then
       echo -e "${GREEN}${es}${NONE}"
   else
       echo -e "${RED}${es}${NONE}"
   fi
}

get_path(){
    #dummy function
    echo "PATH"
}

PROMPT_COMMAND='exitStatus=$(get_exit_status)'

以下给出了正确的 exitStatus 但颜色变量未扩展:

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

然而,下面的给了我颜色,但退出状态没有更新:

PS1="${RED}\h $(get_path) ${exitStatus}${NONE} "

这样做的正确方法是什么?我该如何解决这个问题,以便 exitStatus 和颜色都起作用?

答案1

吉尔斯指出了你的主要问题,但我想尝试以不同的方式解释它。

Bash 解释了特殊提示转义仅有的展开提示中的任何变量。这意味着\e在从提示符扩展的变量中使用不起作用,即使它可以直接在PS1.

例如,这按预期工作,并给出红色文本:

PS1='\e[1;31m this is in red '

但这不是,它只是\e在提示中添加了一个文字:

RED='\e[1;31m'
PS1="$RED not in red "

如果要将颜色转义存储在变量中,可以使用 ANSI-C 引号 ( $'...') 将文字转义字符放在变量中。

为此,您可以更改GREENRED和的定义NONE,因此它们的值是实际的转义序列。

GREEN=$'\033[1;32m'
RED=$'\033[1;31m'
NONE=$'\033[m'

如果你这样做,你的第PS1一个单引号应该可以工作:

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

然而,这样你就会遇到第二个问题。

尝试运行它,然后按Up Arrow,然后按Home,光标将不会返回到行的开头。

要解决此问题,请更改PS1为包含\[\]围绕颜色转义序列,例如

PS1='\[${RED}\]\h $(get_path) $?\[${NONE}\] '

您不能get_exit_status在这里正确使用,因为它的输出包含打印(退出代码)和非打印字符(颜色代码),并且无法在提示中正确标记它。放置\[...\]会将其标记为未完整打印,这是不正确的。您必须更改该函数,以便它只打印正确的颜色代码,然后\[...\]在提示中将其括起来。

答案2

当您运行时PS1='${RED}\h $(get_path) ${exitStatus}${NONE} 'PS1变量设置为${RED}\h $(get_path) ${exitStatus}${NONE},其中仅\h是提示转义序列。提示序列被扩展(产生${RED}darkstar $(get_path) ${exitStatus}${NONE}),shell 执行通常的扩展,例如变量扩展。您会看到一个类似于 的显示提示\e[1;31mdarkstar PATH 0\e[m。一路上没有任何东西将\e序列扩展为实际的转义字符。

当您运行时PS1="${RED}\h $(get_path) ${exitStatus}${NONE} ",该PS1变量被设置为\e[1;31m\h PATH 0\e[m。变量REDexitStatusNONE在赋值时展开。然后提示包含三个提示转义序列(\e\h、 和\e再次)。此阶段没有可扩展的 shell 变量。

为了查看颜色,您需要颜色变量包含实际的转义字符。你可以这样做:

RED=$'\033[1;31m'
NONE=$'\033[m'
PS1='\[${RED}\]\h \w $?\[${NONE}\] '

$'…'扩展反斜杠八进制序列和一些反斜杠字母序列,例如\n,但不包括\e。我对您的提示做了另外三处更改:

  • 使用\[…\]非打印序列,例如颜色更改命令。否则你的显示最终会出现乱码,因为 bash 无法计算出提示符的宽度。
  • \w是一个内置的转义序列,用于打印当前目录。
  • 如果您一开始$?就没有 ,则不需要在提示中显示任何复杂的内容。PROMPT_COMMAND

答案3

尝试:

PS1='`exitStatus=$?;if [ $exitStatus -eq 0 ];then echo "\['${GREEN}'\]";else echo "\['${RED}'\]";fi;echo "\h $(get_path) ${exitStatus}${NONE}"`'

答案4

干得好- 这对 Ubuntu 和其他 Linux(Linuxen?)中的我(TM)有效。

放入退出代码检测的原因$PS1是一台主机在读取 .bashrc 之前设置了只读$PROMPT_COMMAND

相关内容