有时候,我看到脚本中使用的所有的引用一些文字,这些不同的方式:"..."
,'...'
,$'...'
,和$"..."
。为什么要使用这么多不同类型的报价?
他们的行为有所不同还是会影响我在他们里面可以做什么?
有时候,我看到脚本中使用的所有的引用一些文字,这些不同的方式:"..."
,'...'
,$'...'
,和$"..."
。为什么要使用这么多不同类型的报价?
他们的行为有所不同还是会影响我在他们里面可以做什么?
Answers:
所有这些都意味着不同的东西,您可以在其中编写不同的内容(或相同的内容,但含义不同)。不同种类的引号解释其中的不同转义序列(\something
),或者允许或不允许变量插值($something
)和其他种类的扩展。
简而言之:
'...'
完全是字面意义。"..."
允许变量和嵌入式引号字符。 $'...'
执行字符转义,如\n
,但不扩展变量。$"..."
适用于Bash和ksh中的人工语言翻译。无论您在单引号之间写的内容是什么,都不会被处理。反斜杠和美元符号在那里没有特殊含义。这意味着您不能反斜杠转义字符(包括其他单引号!),插入变量或使用任何其他shell功能。
所有这些示例实际上导致了引号之间的内容:
'hello world' => hello world
'/pkg/bin:$PATH' => /pkg/bin:$PATH
'hello\nworld' => hello\nworld
'`echo abc`' => `echo abc`
'I\'dn\'t've' => I\dn'tve
最后一个很复杂-有两个单引号字符串和一些未引号的文本一起运行。第一个包含I\
。未加引号的文本dn\'t
包含一个单引号,该引号在shell级别进行了转义,因此它不会以引号引起来,而是作为文字字符(因此,dn't
)包含在内。最后引用的字符串是just ve
。所有这些都以外壳程序正常工作的方式组合成一个单词。
组合文字文本和变量的一种常见用法是像这样将它们一起运行:
'let x="'$PATH\"
将导致
let x="/usr/bin:/bin"
作为一个单词(最好用双引号$PATH
,以防万一- 否则可能会处理变量值中的空格或小写字符 -但出于可读的运行示例,我没有)。
在双引号内,将处理两种扩展,并且可以使用反斜杠转义字符以防止扩展或转义被处理。
双引号内发生两种类型的扩展:
$
(参数扩展$abc
和${abc}
,命令替换$(...)
和算术扩展$((...))
)开头的代码;`abc`
;在引号内,反斜杠可以通过将其放在$
or 前面来抑制这些扩展`
。它也可以转义用双引号引起来,因此\"
仅"
在您的字符串中包含,或其他反斜杠。所有其他反斜杠都按原样保留-没有转义符可以产生其他字符,并且不会将其删除。
这些示例中的一些行为与以前不同,而有些则没有:
"hello world" => hello world
"/pkg/bin:$PATH" => /pkg/bin:/bin:/usr/bin
"hello\nworld" => hello\nworld
"hello\\nworld" => hello\nworld
"`echo abc`" => abc
"I\'dn\'t've" => I\'dn\'t've
"I'dn't've" => I'dn't've
"I\"dn\"t've" => I"dn"t've
这种引用允许处理C样式的反斜杠转义,但不能处理嵌入的变量或替换。这是唯一支持字符转义的报价。
这是ksh的扩展,现在在Bash,zsh和其他一些Shell中也受支持。这不是还没有 POSIX标准,因此最大便携脚本不能使用它的一部分,但猛砸或ksh脚本是免费的。
:所有这些逃逸的可以用它们的C的含义使用\a
,\b
,\f
,\n
,\r
,\t
,\v
,和字面逃逸\\
,\'
,\"
,和\?
。它们还支持扩展名\e
(转义符)以及Bash和ksh \cx
(由Ctrl-x输入的内容,例如\cM
回车)。壳具有自己的一系列次要扩展。
它还允许四种通用字符转义:
\nnn
,八进制值nnn的单个字节\xHH
,具有十六进制值HH的单个字节\uHHHH
,其十六进制索引为HHHH的Unicode代码点\UHHHHHHHH
,其十六进制索引为HHHHHHHH的Unicode代码点所有这些数字在第一个数字之后都是可选的。
$
并且`
没有任何意义,并且会原样保留,因此您不能在其中包含变量。
$'hello world' => hello world
$'/pkg/bin:$PATH' => /pkg/bin:$PATH
$'hello\nworld' => hello
world
$'`echo abc`' => `echo abc`
$'I\'dn\'t\'ve' => I'dn't've
$'\U1f574\u263A' => 🕴☺
大多数这些逃逸的,你可以模拟使用的printf
命令,虽然POSIX只需要\\
,\a
,\b
,\f
,\n
,\r
,\t
,\v
,和\nnn
在那里工作。您可以使用命令替换嵌入printf
如果需要的话里面的双引号:"Path:$(printf '\t')$PATH"
。
这是特定于ksh和Bash的扩展,用于本地化自然语言文本字符串,并在消息目录中的引号内查找部分。它首先执行所有双引号扩展。如果在翻译数据库中找不到该字符串,则将其用作自己的翻译。内置的假设是字符串是英语的。
您可能不想使用它,但是如果看到它,通常可以将其视为常规双引号。
需要注意的一点是,没有一种引用允许嵌入式参数扩展和嵌入式字符转义。在大多数情况下,使用printf
以下方法会更好(更安全):
printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"
这样可以清楚地区分哪些部分需要转义字符,哪些是数据值。
另一个是所有这些引号样式都在shell中创建单个“单词”,除非 在双引号内使用$@
了数组扩展${x[@]}
。两种单引号形式都始终是一个词,以后再也不会扩展。
$"..."
也来自ksh93,已在2.0中添加到bash中。
\cX
在zsh
。这是\CX
或\C-X
有(\c
已经有特殊含义echo
)
'let x="'$PATH\"
是错误的清单环境比其他炮弹zsh
如$PATH
没有加引号(所以会受到分裂+,你不会想在这里水珠)。