使用变量存储 PS1 的终端颜色代码?

Ism*_*awi 33 bash prompt terminal environment-variables

在我的.bashrc. 它看起来像这样:

PS1='\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ '
Run Code Online (Sandbox Code Playgroud)

其中virtual_envgit_branch是在标准输出上输出内容的 bash 函数。

现在,为了更易于阅读和修改,我想将颜色代码存储在变量中并引用它们,而不是将它们直接嵌入到PS1. 所以我有一堆这样的变量:

GREEN="\[\033[32m\]"
YELLOW="\[\033[33m\]"
RESET="\[\033[0m\]"
Run Code Online (Sandbox Code Playgroud)

我希望能够写出类似的东西:

PS1='\u@\h:\w${YELLOW}$(virtual_env)${GREEN}$(git_branch)${RESET}$ '
Run Code Online (Sandbox Code Playgroud)

但这不起作用——颜色代码显示在提示中,就像它们被转义一样。如果我使用双引号代替 for PS1,颜色可以正常工作,但只有在我这样做时提示才会改变source ~/.bashrc

我尝试了其他我见过的人做的事情——使用printf,使用单引号作为颜色,将\[\]放入PS1而不是颜色变量,但似乎没有任何效果。

如何为颜色代码使用变量?

phe*_*mer 20

解决方案是让 shell 在定义提示时替换颜色变量,而不是函数。为此,请使用您最初尝试的双引号,但对命令进行转义,以便在绘制提示之前不会对它们进行评估。

PS1="\u@\h:\w${YELLOW}\$(virtual_env)${GREEN}\$(git_branch)${RESET}$ "
Run Code Online (Sandbox Code Playgroud)

注意每个命令上的\之前$()

如果我们回应这一点,我们会看到:

echo "$PS1"
\u@\h:\w\[\033[33m\]$(virtual_env)\[\033[32m\]$(git_branch)\[\033[0m\]$ 
Run Code Online (Sandbox Code Playgroud)

如您所见,颜色变量被替换,但命令没有被替换。


Cel*_*ada 7

问题是您的变量GREEN包含由“反斜杠括号反斜杠零三三”等组成的文字字符串。它不包含例如让您的终端改变颜色所需的 ASCII 转义字符。

您可以手动将控制字符放入GREEN(andYELLOWRESET) 中,但更好的选择是首先使用tput,这样您就不需要硬编码任何内容并且您将支持任何终端类型。

GREEN="$(tput setaf 2)"
YELLOW="$(tput setaf 3)"
RESET="$(tput setaf 0)"
Run Code Online (Sandbox Code Playgroud)

将“反斜杠零三三”等直接放入其中的原因PS1是某些反斜杠序列的解释是bash提示的功能(请参阅手册中的提示部分。此替换发生参数扩展,命令之前但是,替换、算术扩展和引号删除,因此它不适用于所有其他操作的结果。

  • 这样做时,您需要将颜色变量包裹在 `$PS1` 内的 `\[\]` 中。例如:`PS1='\u@\h:\w\[${YELLOW}\]'`。如果你不这样做,你最终会得到一个长命令,它会换行到下一行,你会遇到各种各样的问题。shell 使用 `\[\]` 来确定哪些字符是不可打印的,因此它不会将它们计入提示长度的计算中。它需要这样做,以便在超过终端宽度时可以正确绘制线条。 (5认同)