美元符号在Bash中如何影响单引号?

100
我需要从Bash命令行将一个字符串作为参数传递给程序,例如:
program "don't do this"

这个字符串可能包含任何字符,比如 '$', '\' 等等,我不希望 Bash 对其进行任何修改。因此,我考虑使用单引号。

然而,以下内容无法正常工作:

 program 'don\'t do this'            //escape doesn't work in single quote

以下两个工作:

 program $'dont\'t do this'          //seems fine, but any other side effects?
 program 'dont'\''do this'           //breaking into 3 parts

第一种方法似乎更好,因为它需要较少的预修改(将美元符号放在前面并将每个\替换为\\),但我不知道美元符号可能会产生什么其他影响。
我已经通过谷歌搜索,但我找不到我需要的...

11
为了更好地理解 $'...' 的例子,请查看 bash info page 的第一段。 - suvayu
1
感谢您发布这个问题。这对于理解如何对齐制表符分隔的记录(即cat myData.tsv | column -t -s$'\t')非常重要。 - Sridhar Sarnobat
3个回答

130
它会被解释为转义序列。
$ echo $'Name\tAge\nBob\t24\nMary\t36'
Name    Age
Bob     24
Mary    36

在这些序列被展开后,结果会用单引号括起来,就好像美元符号不存在一样。


+1 很好的发现。我猜这是因为变量名被扩展了? - Aaron Digulla
5
不,这是因为$'...'有定义的行为。 - Ignacio Vazquez-Abrams
如果这就是 $'' 所做的一切,那这正是我所需要的! - user1206899
3
这就是 $' 的作用。它会扩展 POSIX 字符串转义符(以及其他一些):\a = BEL (响铃,"警报"),\b = BS (退格),\cX = control+X (例如,\cG\a 相同),\e = ESC (转义),\f = FF (换页),\n = LF (换行),\r = CR (回车),\t = HT (水平制表符),\v = VT (垂直制表符)。 - Mark Reed
2
也许已经晚了,但为什么不使用双引号呢? - Snusifer
2
@Snusifer 双引号会完全扩展美元符号,也就是说 "foo $(echo pwn > /tmp/pwned)" 将写入文件 /tmp/pwned。这是为了简单地替换转义而付出的高昂代价 :-) 然而,这是一个 bashism,如果你想保持 POSIX /bin/sh 的可移植性,你需要在那里手动完成这个操作。 - ljrk

45

在BASH中,使用$作为前缀告诉它尝试查找该名称的变量。$'是一种特殊语法(在这里完全解释),可以启用ANSI-C字符串处理。在这种情况下,单引号不是“直接取值直到下一个单引号”。使用它应该是非常安全的。缺点是它只适用于BASH,并且相当不常见,因此许多人会想知道它的含义。

更好的方法是使用单引号。如果您需要在字符串中使用单引号,则需要将其替换为'\''。这结束了先前的单引号字符串,在其中添加了一个单引号(\'),然后开始一个新的单引号字符串。此语法适用于Bourne shell的任何后代,易于理解,大多数人很快就能认出模式。

替换每个单引号为 '"'"',它的含义是“终止当前的单引号字符串,添加只包含一个单引号的双引号字符串,重新开始单引号字符串”,这样可以避免使用转义字符,看起来更加对称美观。如果需要在双引号字符串中使用双引号,则可以反过来使用 "'"'"

3
经常看到 '"'"' 这样的符号,例如 'the dog'"'"'s tail' - William Pursell
$'SHELL'和$'LANG'不会“失败”。$'中的美元符号具有不同的功能。我会说'''是一种正确的方式。 - jox
1
$'...'的目标是被纳入POSIX标准。[http://mywiki.wooledge.org/Bashism] [http://austingroupbugs.net/view.php?id=249] - go2null
一直在搜索这个术语,直到我找到了这个答案中的链接。 - Franklin Yu

-2
你不会找到比这更快或更高效的方式:
eval RESULT=\$\'$STRING\'

首先,这就是eval存在的原因,你可以避免在各个地方分叉子进程的疯狂成本,正如之前的答案所建议的那样。你的例子:
$ foo='\u25b6'
$ eval bar=\$\'$foo\'
$ echo "$bar"

1
这是对Bash语法含义的误解。$'...'C风格字符串,它遵循不同于常规字符串的引用规则,如本页其他答案所述。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接