使用 $'...'、$"..."、'...' 和 "..." 的文本颜色

使用 $'...'、$"..."、'...' 和 "..." 的文本颜色

从我记事起,我个人在使用 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"打印正常颜色的$,然后打印红色文本。这就是您运行的shLinux 的样子。在其他一些 Linux 系统中您可能会得到不同的结果。

在 Mac 上,安装的 shellsh实际上是带 set 的 Bash (安装时已禁用的xpg_echoshell ),或者在较新的 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语句中的变量。

相关内容