从我记事起,我个人在使用 bash 时使用以下方法来更改输出文本的颜色:
red=$'\033[1;31m'
nc=$'\033[0m'
echo "${red}This is red text$nc"
无论是在 macOS 还是 Linux 上使用,它总是对我有用。出于好奇,为了更好地理解它为什么起作用,我做了一些研究并发现了一些不包括$
(red='\033[1;31m'
)的答案/示例。经过一些测试,如果我不使用$
,输出颜色不会更改为红色,而只是打印字符串。但是,当使用sh
而不是执行它时bash
,文本确实会改变颜色。有人可以帮助我理解这是为什么吗?
我还用双引号而不是单引号对其进行了测试,并且它似乎仅在使用时才有效sh
。我将在下面发布示例。
这是我使用的脚本和代码:
#!/bin/bash
red=$'\033[1;31m'
nc=$'\033[0m'
echo "${red}Test 1$nc"
echo ""
##########################
red=$"\033[1;31m"
nc=$"\033[0m"
echo "${red}Test 2$nc"
echo ""
##########################
red='\033[1;31m'
nc='\033[0m'
echo "${red}Test 3$nc"
echo ""
##########################
red="\033[1;31m"
nc="\033[0m"
echo "${red}Test 4$nc"
echo ""
使用 bash 和 sh 在 macOS 上输出:
Linux 上同时使用 bash 和 sh 的输出:
答案1
这里最主要的是,为了让终端识别控制序列,发送给终端的输出必须包含 ESC 字符,然后[1;31m
. ESC 是一个控制字符,我们通常不会在 shell 脚本中按原样显示它,而是使用反斜杠转义符\033
来使用其八进制字符代码(十进制 27、八进制 033 或十六进制 0x1b)来表示该字符。 )。其余的只是普通角色。
现在,反斜杠转义符需要在某个时候更改为原始 ESC 字符。有两个地方可能会发生这种情况:对变量的赋值和打印它的命令。
在支持它的 shell 中,$'...'
引号的类型已经解释了转义,因此在 后red=$'\033[...'
,变量本身包含原始 ESC 字符。这不是标准的 POSIX 功能,在不支持它的 shell 中,它会分配原始美元符号,然后是反斜杠,033[
等等。另一方面, red='\033[...'
只会分配反斜杠033[
等,从不解释转义。看
($"..."
,并且"..."
永远不要解释转义,并且带有美元的转义符也是非标准的,因此可能会将文字美元符号留在不支持它的 shell 中。)
然后,第二步是印刷。在某些 shell 中echo
会展开反斜杠转义。在其他情况下则不然。其中一些也有echo -e
同样的情况。 Bashecho
默认情况下不会这样做,但是通过设置xpg_echo
...它会这样做。 Zshecho
确实解释了它们。看
因此,在常用的 Linux 桌面发行版上的常用 Bash 中,如果xpg_echo
未设置 where ,red=$'\033[1;31m'; echo "${red}text"
则会在作业上生成 ESC 并打印红色文本,但red='\033[1;31m'; echo "${red}text"
不会在作业或 中生成它echo
,而只是\033[1;31mtext
以正常颜色打印。
在 Debian/Ubuntu 上,sh
是 Dash,其中$'...'
不支持引号,但echo
会解释反斜杠,因此 red=$'\033[1;31m'; echo "${red}text"
打印正常颜色的$
,然后打印红色文本。这就是您运行的sh
Linux 的样子。在其他一些 Linux 系统中您可能会得到不同的结果。
在 Mac 上,安装的 shellsh
实际上是带 set 的 Bash (安装时已禁用的xpg_echo
shell ),或者在较新的 macOS 版本中安装的 zsh。bash
尽管开始sh
尝试使它们更加兼容 POSIX,他们仍然支持引号$'...'
,因此两者red=$'\033[1;31m'; echo "${red}text"
都red='\033[1;31m'; echo "${red}text"
打印红色文本。
还困惑吗?red='\033[1;31m'; printf "%b\n" "${red}text";
应该可以在所有类似 POSIX 的 shell 中工作。告诉%b
它处理参数中的反斜杠转义符,因此“文本”中的任何内容都会得到处理。
答案2
Linux 我可以回答。我认为关键不在于如何使用 ANSI 转义序列,而在于如何声明变量。
red=$'\033[1;31m' # a dollar sign and an ANSI escape sequence
red=$"\033[1;31m" # a dollar sign and an ANSI escape sequence
red='\033[1;31m' # only an ANSI escape sequence
red="\033[1;31m" # only an ANSI escape sequence
在 中sh
,当您打印时
echo "${red}some text"
您打印变量的值red
,然后打印一些文本。在前两种情况下,ANSI 转义序列之前有一个美元符号,因此它不受颜色变化的影响。
在 中bash
,当您打印时
echo -e "${red}some text"
ANSI 转义序列被解释,但带有
echo "${red}some text"
不解释 ANSI 转义序列,而是按字面打印字符,但可能会在语句“之前”进行转换echo
。
在你的中sh
有另一个内置函数,echo
它显然可以解释 ANSI 转义序列,而无需选项-e
。
bash
如果您查看 的十六进制值,就可以解释第一个示例和其他示例之间的差异red
。查看我编辑的脚本,
#!/bin/bash
red=$'\033[1;31m'
nc=$'\033[0m'
hexdump <<< "$red"
echo $1 "${red}Test 1$nc"
echo ""
##########################
red=$"\033[1;31m"
nc=$"\033[0m"
hexdump <<< "$red"
echo $1 "${red}Test 2$nc"
echo ""
##########################
red='\033[1;31m'
nc='\033[0m'
hexdump <<< "$red"
echo $1 "${red}Test 3$nc"
echo ""
##########################
red="\033[1;31m"
nc="\033[0m"
hexdump <<< "$red"
echo $1 "${red}Test 4$nc"
echo ""
echo -e
我还通过将该选项添加到脚本中来方便查看,因此请尝试两者
bash box2
和
bash box2 -e
例如,我建议您声明不带任何美元符号的“着色”变量
red='\033[1;31m'
并且仅当您使用美元符号时使用例如echo
语句中的变量。