参数扩展(变量扩展)和引号内的引号

参数扩展(变量扩展)和引号内的引号

在 (Unix) shell 中工作时,有时我需要用双引号括住单引号或反之亦然,例如写类似"foo 'bar baz' moo"或 的内容'foo "bar baz" moo'。这可能是因为

  • 生成的字符串将被解析再次(例如使用eval,使用由 运行的 shell watch,使用由 在某些远程服务器上运行的 shellsshd等等)并且这些内部引号对于在第二次解析期间区分实际参数至关重要;
  • 或者我只是需要原始论点包含引号,无论出于何种原因。

bar baz如果用 来代替“我”,则会出现一些歧义$variable。这是POSIX 的说法

2.2.2 单引号

将字符括在单引号 ( '') 中应保留单引号内每个字符的字面值。单引号内不能出现单引号。

2.2.3 双引号

将字符括在双引号 ( "") 中将保留双引号内所有字符的文字值,但反引号、<美元符号> 和 <反斜杠> 字符除外,如下所示:

$
应保留其特殊含义,引入参数扩展[…]、命令替换的一种形式[…]和算术扩展[…]。

[…]

$variable对于双引号内的单引号内(或单引号内的双引号内)适用哪条规则并不十分明显,因此我想问:

  1. 哪条规则适用于:

    • variable=123
      echo "'$variable'"
      
    • variable=123
      echo '"$variable"'
      

    (我知道只要尝试就可以轻松回答这个问题,这将是一项合理的研究工作。我决定将这项努力投入到下面的社区维基答案中)。

  2. 有没有什么例外、怪癖或者意外?

    (请注意下面有一个社区维基答案。不要添加具有另一个例外或怪癖的单独答案,而是考虑为社区维基做出贡献)。

答案1

适用哪条规则?

只需尝试:

  • $ variable=123
    $ echo "'$variable'"
    '123'
    $
    
  • $ variable=123
    $ echo '"$variable"'
    "$variable"
    $
    

所以外部引号很重要。常见的 shell 行为方式相同:,,,,,…sh这是因为以下一般规则:bashdashzsh

如果当前字符是<反斜杠>、单引号或双引号并且未被引用,则它将影响后续字符的引用,直到引用文本的末尾。

(来源)

只有外引号不被引用,规则适用于它们。内引号被引用,它们不会影响后续字符。


有没有什么例外、怪癖或者意外?

(好吧,echo可能会带来一些惊喜,见为什么printf比 更好echo不过,这是一个单独的问题。为了便于阅读,答案使用了echo安全值$variable)。

  1. 上述代码给出了'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
      
  2. 问题注意到$在双引号中保留了其特殊含义。这很重要:

    引号字符串内的输入字符(这些字符也括在$(和 匹配之间))不受双引号的影响,而是定义在$(…)扩展单词时其输出替换 的命令。

    (来源)

    这意味着,$(…)尽管有外部双引号,但内部引用应该被单独考虑。事实上:

    $ variable=123
    $ echo "$(echo 'foo $variable')"
    $ #            ^             ^   single-quotes matter!
    foo $variable
    $
    

    echo $(stuff)注意总体来说糟糕的代码;它在这里阐明当前问题)。

    在这两种情况下:

    • echo "'$variable'"(已尝试上述方法)
    • echo "$(echo 'foo $variable')"(此处讨论)

    双引号内有$variable单引号,但$(…)变化很大。情况类似echo "`echo 'foo $variable'`"(尽管$(…)和反引号并不完全等同)。

相关内容