在 (Unix) shell 中工作时,有时我需要用双引号括住单引号或反之亦然,例如写类似"foo 'bar baz' moo"
或 的内容'foo "bar baz" moo'
。这可能是因为
- 生成的字符串将被解析再次(例如使用
eval
,使用由 运行的 shellwatch
,使用由 在某些远程服务器上运行的 shellsshd
等等)并且这些内部引号对于在第二次解析期间区分实际参数至关重要; - 或者我只是需要原始论点包含引号,无论出于何种原因。
bar baz
如果用 来代替“我”,则会出现一些歧义$variable
。这是POSIX 的说法:
2.2.2 单引号
将字符括在单引号 (
''
) 中应保留单引号内每个字符的字面值。单引号内不能出现单引号。2.2.3 双引号
将字符括在双引号 (
""
) 中将保留双引号内所有字符的文字值,但反引号、<美元符号> 和 <反斜杠> 字符除外,如下所示:
$
应保留其特殊含义,引入参数扩展[…]、命令替换的一种形式[…]和算术扩展[…]。[…]
$variable
对于双引号内的单引号内(或单引号内的双引号内)适用哪条规则并不十分明显,因此我想问:
哪条规则适用于:
-
variable=123 echo "'$variable'"
-
variable=123 echo '"$variable"'
(我知道只要尝试就可以轻松回答这个问题,这将是一项合理的研究工作。我决定将这项努力投入到下面的社区维基答案中)。
-
有没有什么例外、怪癖或者意外?
(请注意下面有一个社区维基答案。不要添加具有另一个例外或怪癖的单独答案,而是考虑为社区维基做出贡献)。
答案1
适用哪条规则?
只需尝试:
-
$ variable=123 $ echo "'$variable'" '123' $
-
$ variable=123 $ echo '"$variable"' "$variable" $
所以外部引号很重要。常见的 shell 行为方式相同:,,,,,…sh
这是因为以下一般规则:bash
dash
zsh
如果当前字符是<反斜杠>、单引号或双引号并且未被引用,则它将影响后续字符的引用,直到引用文本的末尾。
只有外引号不被引用,规则适用于它们。内引号被引用,它们不会影响后续字符。
有没有什么例外、怪癖或者意外?
(好吧,echo
可能会带来一些惊喜,见为什么printf
比 更好echo
?不过,这是一个单独的问题。为了便于阅读,答案使用了echo
安全值$variable
)。
上述代码给出了
'123'
或"$variable"
。如果我们需要"123"
或怎么办'$variable'
?要得到
"123"
:variable=123 echo "\"$variable\"" # ^^ ^^ escaped inner quotes
或者
variable=123 echo '"'"$variable"'"' # 1 12 23 3 outer quotes (numbered pairs) # ^ ^^^^^^^^^ ^ quoted fragments
要得到
'$variable'
:variable=123 echo "'"'$variable'"'" # 1 12 23 3 outer quotes (numbered pairs) # ^ ^^^^^^^^^ ^ quoted fragments
问题注意到
$
在双引号中保留了其特殊含义。这很重要:引号字符串内的输入字符(这些字符也括在
$(
和 匹配之间)
)不受双引号的影响,而是定义在$(…)
扩展单词时其输出替换 的命令。这意味着,
$(…)
尽管有外部双引号,但内部引用应该被单独考虑。事实上:$ variable=123 $ echo "$(echo 'foo $variable')" $ # ^ ^ single-quotes matter! foo $variable $
(
echo $(stuff)
注意总体来说糟糕的代码;它在这里阐明当前问题)。在这两种情况下:
echo "'$variable'"
(已尝试上述方法)echo "$(echo 'foo $variable')"
(此处讨论)
双引号内有
$variable
单引号,但$(…)
变化很大。情况类似echo "`echo 'foo $variable'`"
(尽管$(…)
和反引号并不完全等同)。