“…”,“…”,$“…”和$“…”引号之间有什么区别?


49

有时候,我看到脚本中使用的所有的引用一些文字,这些不同的方式:"..."'...'$'...',和$"..."。为什么要使用这么多不同类型的报价?

他们的行为有所不同还是会影响我在他们里面可以做什么?


1
可能跨站点重复。该答案提供了所有不同类型引号的语义的摘要(或链接)。
chepner

Answers:


66

所有这些都意味着不同的东西,您可以在其中编写不同的内容(或相同的内容,但含义不同)。不同种类的引号解释其中的不同转义序列(\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,以防万一- 否则可能会处理变量中的空格或小写字符 -但出于可读的运行示例,我没有)。


“双引号”

在双引号内,将处理两种扩展,并且可以使用反斜杠转义字符以防止扩展或转义被处理。

双引号内发生两种类型的扩展:

在引号内,反斜杠可以通过将其放在$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

$'ANSI-C引号'

这种引用允许处理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中。
斯特凡Chazelas

有没有\cXzsh。这是\CX\C-X有(\c已经有特殊含义echo
斯特凡Chazelas

'let x="'$PATH\"是错误的清单环境比其他炮弹zsh$PATH没有加引号(所以会受到分裂+,你不会想在这里水珠)。
斯特凡Chazelas

你可能想澄清,你说的光辉般的炮弹,报价处理是在csh,RC,鱼不同的...
斯特凡Chazelas

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.