带有最后退出代码的Bash提示

fer*_*lin 57 linux bash prompt

所以,我一直在尝试通过bash提示进行自定义,以便它看起来像

[feralin@localhost ~]$ _
Run Code Online (Sandbox Code Playgroud)

与颜色.我设法得到恒定的颜色(每次看到提示时颜色相同)但我希望用户名('feralin')显示为红色,而不是绿色,如果最后一个命令具有非零退出状态.我提出了:

\e[1;33m[$(if [[ $? == 0  ]]; then echo "\e[0;31m"; else echo "\e[0;32m"; fi)\u\e[m@\e[1;34m\h \e[0;35m\W\e[1;33m]$ \e[m
Run Code Online (Sandbox Code Playgroud)

但是,根据我的观察,$(if ...; fi)似乎在.bashrc运行时评估一次,结果在之后永远被替换.这使得名称始终为绿色,即使最后一个退出代码非零(如,echo $?).这是发生了什么?或者我的提示是否只是其他错误?长问题简介,我如何获得使用最后退出代码的提示?

dem*_*ure 98

当您开始在复杂的PS1上边界时,您可以考虑使用PROMPT_COMMAND.
有了这个,你将它设置为一个函数,它将在每个命令后运行以生成提示.

您可以尝试以下内容 ~/.bashrc

PROMPT_COMMAND=__prompt_command # Func to gen PS1 after CMDs

__prompt_command() {
    local EXIT="$?"             # This needs to be first
    PS1=""

    local RCol='\[\e[0m\]'

    local Red='\[\e[0;31m\]'
    local Gre='\[\e[0;32m\]'
    local BYel='\[\e[1;33m\]'
    local BBlu='\[\e[1;34m\]'
    local Pur='\[\e[0;35m\]'

    if [ $EXIT != 0 ]; then
        PS1+="${Red}\u${RCol}"      # Add red if exit code non 0
    else
        PS1+="${Gre}\u${RCol}"
    fi

    PS1+="${RCol}@${BBlu}\h ${Pur}\W${BYel}$ ${RCol}"
}
Run Code Online (Sandbox Code Playgroud)

这应该做你想要的声音.如果你想看看我用我的函数做的所有事情,看看我的bashrc的子文件__prompt_command.

  • 在Mac上,您需要`PROMPT_COMMAND ="__ prompt_command; $ {PROMPT_COMMAND}"`以启用当前工作目录中的新选项卡/窗口仍然有效.默认情况下,PROMPT_COMMAND = update_terminal_cwd`,记录cwd. (5认同)
  • 我建议为“EXIT”使用至少一个小写字符的变量名,作为向前兼容的做法。参见 http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html,第四段——全大写名称的命名空间用于对系统或外壳有意义的变量;坚持小写名称可防止在仅尝试分配 shell 变量时覆盖环境变量或 shell 内置变量。当然,覆盖是临时的本地声明,这使得这里的问题比平常少,但仍然不理想。 (3认同)
  • Bash 变量“PIPESTATUS”提供有关上次执行的命令或管道的更多信息。如果所有命令都正确执行,`${PIPESTATUS[@]}` 将是一串零,如 `0 0 0`,否则它将有非零,如 `0 127 1`。可以使用 `if $(echo ${PIPESTATUS[@]} | grep -qEe '^0( 0)*$'); 检查是否成功。然后回声“好”;否则回显“坏”;fi`。 (3认同)

hel*_*ios 16

如果您不想使用prompt命令,则需要考虑两件事:

  1. 得到$的价值?在其他任何事情之前,否则它将被覆盖
  2. 转义PS1中的所有$(因此在分配时不会对其进行评估)

使用变量的工作示例

PS1="\$(VALU="\$?" ; echo \$VALU ; date ; if [ \$VALU == 0 ]; then echo zero; else echo nonzero; fi) " 
Run Code Online (Sandbox Code Playgroud)

没有变量的工作示例

这里的if必须是第一件事,在任何覆盖它的命令之前$?.

PS1="\$(if [ \$? == 0 ]; then echo zero; else echo nonzero; fi) "
Run Code Online (Sandbox Code Playgroud)

注意如何\$()转义,因此它不会立即执行,但每次使用PS1时都会执行.也是所有的用途\$?

  • 虽然我更喜欢简单的三元符号:`export PS1 ="\ $([\ $?== 0] &&echo✅||echo⚠️)\ h:\ W\u \n\$"` (3认同)
  • 太棒了!自1995年以来,我一直是个肮脏的老家伙,对我来说从来没有在PS1中使用命令替换。谢谢。 (2认同)
  • 当使用像 python 的“virtualenv”这样的工具时,这个解决方案特别有趣,这些工具在激活时为“PS1”变量添加信息前缀。使用“PROMPT_COMMAND”是行不通的! (2认同)
  • 看来如果您使用“\${PIPESTATUS[-1]}”,即使它不是“PS1”中的第一件事,您也可以获得最后一个命令的退出状态。 (2认同)

Ale*_*hek 11

紧凑型解决方案:

PS1='... $(code=${?##0};echo ${code:+[error: ${code}]})'
Run Code Online (Sandbox Code Playgroud)

这种方法不需要PROMPT_COMMAND(显然这有时会更慢),并且[error: <code>]如果退出代码非零则打印,如果为零则不打印任何内容:

... > false
... [error: 1]> true
... >
Run Code Online (Sandbox Code Playgroud)

[error: ${code}]根据您的喜好更改部分,并${code}作为要打印的非零代码。

请注意,使用 来'确保$()稍后评估 PS1 时(而不是启动 shell 时)执行内联 shell。

\e[01;31m作为奖励,您可以通过在前面和后面添加重置来使其变为红色\e[00m

PS1='... \e[01;31m$(code=${?##0};echo ${code:+[error: ${code}]})\e[00m'
Run Code Online (Sandbox Code Playgroud)

--

怎么运行的:

  • 它使用bash 参数替换
  • 首先,将读取上一个命令的${?##0}退出代码$?
  • 将从头开始##删除任何模式,有效地使结果成为一个空变量(感谢@blaskovicz的技巧)00
  • 我们将其分配给临时code变量,因为我们需要进行另一次替换,并且它们不能嵌套
  • 仅当设置了变量(非空)时才会${code:+REPLACEMENT}打印该部分REPLACEMENTcode
  • 这样我们就可以在它周围添加一些文本和括号,并再次内联引用该变量:[error: ${code}]


Vel*_*kan 7

我想保留默认的Debian颜色,打印确切的代码,并且只在失败时打印它:

# Show exit status on failure.
PROMPT_COMMAND=__prompt_command

__prompt_command() {
    local curr_exit="$?"

    local BRed='\[\e[0;91m\]'
    local RCol='\[\e[0m\]'

    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

    if [ "$curr_exit" != 0 ]; then
        PS1="[${BRed}$curr_exit${RCol}]$PS1"
    fi
}
Run Code Online (Sandbox Code Playgroud)