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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16715103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:00:05  来源:igfitidea点击:

Bash Prompt with Last Exit Code

linuxbashprompt

提问by feralin

So, I've been trying to customize by bash prompt so that it will look like

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

[feralin@localhost ~]$ _

with colors. I managed to get constant colors (the same colors every time I see the prompt) but I want the username ('feralin') to appear red, instead of green, if the last command had a nonzero exit status. I came up with:

与颜色。我设法获得了恒定的颜色(每次看到提示时都是相同的颜色),但是如果最后一个命令的退出状态非零,我希望用户名('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

However, from my observations, the $(if ...; fi)seems to be evaluated once, when the .bashrcis run, and the result is substituted forever after. This makes the name always green, even if the last exit code is nonzero (as in, echo $?). Is this what is happening? Or is it simply something else wrong with my prompt? Long question short, how do I get my prompt to use the last exit code?

但是,根据我的观察,$(if ...; fi)似乎在.bashrc运行时评估了一次,并且结果将永远被替换。这使得名称始终为绿色,即使最后一个退出代码非零(如,echo $?)。这是正在发生的事情吗?或者只是我的提示有其他问题?长问题简短,如何让我提示使用最后一个退出代码?

采纳答案by demure

As you are starting to border on a complex PS1, you might consider using PROMPT_COMMAND.
With this, you set it to a function, and it will be ran after each command to generate the prompt.

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

You could try the following in your ~/.bashrc

你可以在你的 ~/.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}"
}

This should do what it sounds line you want. Take a look a my bashrc's sub fileif you want to see all the things I do with my __prompt_commandfunction.

这应该按照您想要的方式进行。如果您想查看我使用我的函数所做的所有事情,请查看我的 bashrc 的子文件__prompt_command

回答by demure

Improved @demure

改进了@demure

I think this is important because there is not always exit status is 0 or 1.

我认为这很重要,因为退出状态并不总是 0 或 1。

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

回答by Velkan

I wanted to keep default Debian colors, print the exact code, and only print it on failure:

我想保留默认的 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)}\[3[01;32m\]\u@\h\[3[00m\]:\[3[01;34m\]\w\[3[00m\]$ '

    if [ "$curr_exit" != 0 ]; then
        PS1="[${BRed}$curr_exit${RCol}]$PS1"
    fi
}

回答by helios

If you don't want to use the prompt command there's two things you need to take into account:

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

  1. getting the value of $? before anything else, otherwise it'll be overriden
  2. escaping all the $'s in the PS1 (so it's not evaluated when you assign it)
  1. 获得 $ 的价值?在其他任何事情之前,否则它将被覆盖
  2. 转义 PS1 中的所有 $(因此在分配时不会对其进行评估)

Working example using a variable

使用变量的工作示例

PS1="$(VALU="$?" ; echo $VALU ; date ; if [ $VALU == 0 ]; then echo zero; else echo nonzero; fi) " 

Working example without a variable

没有变量的工作示例

Here the if needs to be the first thing, before any command that would override the $?.

这里 if 需要是第一件事,在任何会覆盖$?.

PS1="$(if [ $? == 0 ]; then echo zero; else echo nonzero; fi) "

Notice how the \$()is escaped so it's not executed right away but each time PS1 is used. Also all the uses of \$?

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

回答by Alexander Klimetschek

Compact solution:

紧凑的解决方案:

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

This approach does not require PROMPT_COMMAND(apparently this can be slower sometimes) and prints [error: <code>]if the exit code is non-zero, and nothing if it's zero:

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

... > false
... [error: 1]> true
... >

Change the [error: ${code}]part depending on your liking, with ${code}being the non-zero code to print.

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

Note the use of 'to ensure the inline $()shell gets executed when PS1 is evaluated later, not when the shell is started.

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

As bonus, you can make it colorful in red by adding \e[01;31min front and \e[00mafter to reset:

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

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

--

——

How it works:

这个怎么运作:

  • it uses bash parameter substitution
  • first, the ${?##0}will read the exit code $?of the previous command
  • the ##will remove any 0pattern from the beginning, effectively making a 0result an empty var (thanks @blaskoviczfor the trick)
  • we assign this to a temporary codevariable as we need to do another substitution, and they can't be nested
  • the ${code:+REPLACEMENT}will print the REPLACEMENTpart only if the variable codeis set (non-empty)
  • this way we can add some text and brackets around it, and reference the variable again inline: [error: ${code}]
  • 它使用bash 参数替换
  • 首先,${?##0}将读取$?上一个命令的退出代码
  • ##将删除任何0从一开始的模式,有效地使一个0结果,一个空的VAR(感谢@blaskovicz用于特技)
  • 我们将它分配给一个临时code变量,因为我们需要进行另一个替换,并且它们不能嵌套
  • ${code:+REPLACEMENT}将打印REPLACEMENT部分仅当该变量code被设置(非空)
  • 这样我们就可以在它周围添加一些文本和括号,并再次内联引用该变量: [error: ${code}]