将最后一个命令退出代码设置为 bash 提示符

将最后一个命令退出代码设置为 bash 提示符

我运行的是 Ubuntu 18.04,我想设置 bash 提示符,如下所示:

user:~/Documents [14:22:07] 1 $

我的PS1如下:

ALERT_COLOR="$(tput setaf 1)"

# Display unsuccessful exit codes
function exit_status {
    last_status=$?
    if [[ $last_status != 0 ]]; then
        echo "$ALERT_COLOR[$last_status]"
    fi  
}

parse_git_branch() {
 git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
if [ "$color_prompt" = yes ]; then
 PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\] \[\033[36m\][\t] \[$ALERT_COLOR\]$exit_status \[\033[0;37m\]\$ '
else
 PS1='${debian_chroot:+($debian_chroot)}\u:\w$(parse_git_branch)\$ '
fi
unset color_prompt force_color_prompt

除了退出代码之外,一切都正常。它从不显示退出代码,如果我只是$?在 PS1 中这样做,那么它总是显示为0

答案1

问题在这里:

PS1='...\[$ALERT_COLOR\]$exit_status ...\$ '
                        ^^

那是一个参数扩展,它不会调用您设置的函数。您需要在命令替换中调用该函数,例如$(exit_status), 或 from PROMPT_COMMAND。如果这样做,请注意转义\[ .. \]:Bash 解释它们提示中的其他扩展,因此您必须在提示字符串中对它们进行硬编码(它们不能是变量或提示中扩展的其他内容的一部分)。

如果不扩展变量的提示转义对你来说似乎是倒退的,我不能责怪你。但这就是它的记录方式:

此外,下表描述了可以出现在提示变量中的特殊字符PS1PS4[...] 字符串解码后,通过参数扩展、命令替换进行扩展,[...]

像这样的东西应该有效:

normal_color=$'\033[00m'
red_color=$'\033[41m'
exit_color=$normal_color

set_exit_color() {
    if [ "$?" != 0 ]; then
        exit_color=$red_color
    else
        exit_color=$normal_color
    fi
}

PROMPT_COMMAND=set_exit_color
PS1='\[$exit_color\][$?]\[$normal_color\] \w\$ '

我本以为它需要一个临时变量来保存退出状态,但显然PROMPT_COMMAND不会修改$?提示中扩展的值。如果从提示字符串内部使用命令替换调用该函数,则您需要一个解决方法,因为命令替换的退出代码会生效。像这样的东西:

normal_color=$'\033[00m'
red_color=$'\033[41m'
exit_color=$normal_color

exit_color() {
    exit_code=$?
    if [ "$exit_code" != 0 ]; then
        echo "$red_color"
    else
        echo "$normal_color"
    fi
    return "$exit_code"
}

PS1='\[$(exit_color)\][$?]\[$normal_color\] \w\$ '

我会使用 with 的版本PROMPT_COMMAND,只是为了保存由命令替换引起的子 shell 分叉,但实际上效果很小。

答案2

我喜欢有 3 行提示,所以我这样做:

۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 10:56:52
jackman@jackmanVM:~/tmp
+$ cat ~/.bash_prompt
# ... some other stuff ...

__bash_prompt() {
    local last_status=$1
    local cwd=$( sed "s,^$HOME,~," <<<"$PWD" )
    local user_host_path="${debian_chroot:+($debian_chroot) }$(id -un)@$(hostname -s):$cwd"

    # terminal title
    echo -ne "\e]0;$user_host_path\a"

    # separator and date
    local char="۰"
    printf "%s bash %s " "$(jot -s "" -b "$char" $(( $(tput cols) - 18 )) )" "$char$char"
    date '+%T'

    if ((last_status != 0)); then
        local color_bold='\e[0;1m'
        local color_reset='\e[0m'
        printf "$color_bold[%d]$color_reset " $last_status
    fi

    # user@host, directory, git branch
    printf "%s%s\n" "${user_host_path}$(git_current_branch " (%s)")"
}

# ref: https://stackoverflow.com/questions/1039713/different-bash-prompt-for-different-vi-editing-mode
# a single-line PS1 allows the show-mode-in-prompt inputrc setting to be useful
PROMPT_COMMAND='__bash_prompt $?'
PS1='\$ '

我在 ~/.bashrc 中获取该文件

退出状态显示如下

۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 11:05:10
jackman@jackmanVM:~/tmp
+$ sh -c 'exit 42'
۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 11:05:14
[42] jackman@jackmanVM:~/tmp
+$ false
۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 11:05:16
[1] jackman@jackmanVM:~/tmp
+$ true
۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 11:05:17
jackman@jackmanVM:~/tmp
+$ 

请注意,我在函数中做的第一件事是在执行任何其他命令之前存储最后的退出状态

我使用 PROMPT_COMMAND 输出所有奇特的东西,并且只有一个简单的 PS1,因为我使用 vi 模式,并且我喜欢查看 vi 模式指示器。我也有这个:

۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰۰ bash ۰۰ 10:57:21
jackman@jackmanVM:~/tmp
+$ cat ~/.inputrc
set editing-mode vi

set show-mode-in-prompt on
$if Bash
    # not until bash 4.4, I believe
    # escape sequences: https://stackoverflow.com/a/42107711/7552 
    #set vi-ins-mode-string "+\1\e[5 q\2"
    #set vi-cmd-mode-string ":\1\e[1 q\2"
    set vi-ins-mode-string +
    set vi-cmd-mode-string :
$endif

我用作为我的登录 shell,并且偶尔会进入 ksh,因此我将 shell 的名称放在提示符分隔符中,这样我就可以跟踪我正在输入的内容。

相关内容