BASH - 自定义 PS1 来运行命令

Szy*_*mon 5 colors bash prompt

我想修改我的 PS1 以每次运行一些命令。假设我想要它,如果最后执行的命令成功,它会在 PS1 的末尾添加一个绿色的微笑,否则微笑应该是红色的。
我将它提取到一个函数中:

function exit_smile {

    EXITSTATUS="$?"
    RED="\[\e[1;31m\]"
    GREEN="\[\e[32;1m\]"

    if [ "${EXITSTATUS}" -eq 0 ]
    then
       SMILE="${GREEN}:)"
    else
       SMILE="${RED}:("
    fi

    echo -n "$SMILE"
}
Run Code Online (Sandbox Code Playgroud)

然后在修改 PS1 变量时尝试使用`exit_smile`和,但在修改 PS1 或打印文字而不是颜色时它会执行一次。 例如\$(exit_smile)\[\e...\]

PROMPT="\u@\h \W"
PS1="${PROMPT} \$ \$(exit_smile) ${OFF}\n"
Run Code Online (Sandbox Code Playgroud)

给出username@hostname ~ $ \[\e[32;1m\]:)
我缺少什么?

ilk*_*chu 4

我不确定这在版本(*)之间是否有所改变,但我的 Bash 手册页说

Bash 允许通过插入一些反斜杠转义的特殊字符来自定义这些提示字符串,这些字符的解码如下:

(列表包含\e\[\]

字符串解码后,通过参数扩展、命令替换等进行扩展...

这意味着\[..\]不能来自命令替换,但必须在此之前。

(这也意味着您可以使用\u\w作为命令替换的参数,并且它们会在命令运行之前被替换。而且我不知道放入\[..\]命令替换会做什么......这会以另一种方式更有意义大约。)

因此,我们必须将颜色代码放在单独的扩展中并\[..\]手动保护它们。我将使用变量而不是命令替换,并且还使用扩展$'...'来获取 ESC 字符:

prompt_smile() {
        if [ "$?" = 0 ] ; then
                smile=' :) '
                smilecolor=$'\e[1;32m'
        else
                smile=' :( '
                smilecolor=$'\e[1;31m'
        fi
        normalcolor=$'\e[0m'
}

PROMPT_COMMAND=prompt_smile
PS1='\u@\h \W \$ \[$smilecolor\]$smile\[$normalcolor\]\n'
Run Code Online (Sandbox Code Playgroud)

(*我想知道这一点的原因是,旧的和类似的但没有如此重复的问题\[..\]的答案似乎是从扩展中输出的)