为什么在赋值 `foo=$bar` 时不需要双引号 `$bar`?

为什么在赋值 `foo=$bar` 时不需要双引号 `$bar`?

https://unix.stackexchange.com/a/32227/674

不使用双引号是安全的主要地方是:

  • 在赋值中:(但请注意,在或在数组赋值中 foo=$bar需要双引号,例如);export "foo=$bar"array=("$a" "$b")
  1. $bar这是否意味着赋值时不需要双引号foo=$bar?为什么?

  2. export "foo=$bar"为什么我们需要在数组赋值中使用双引号,例如array=("$a" "$b")

谢谢。

答案1

foo=$bar

安全的因为它是一个任务,以及使用标量赋值语法对标量变量进行赋值。它是标量上下文,只能存储一个值$var,因此 split 或 glob 没有意义$bar。如果扩展产生多个单词,则 shell 需要以某种方式再次组合它们,以便能够将它们作为一个字符串存储在$foo.

当你使用时,情况会有所不同:

foo=($bar)

您分配给数组变量的位置。这是一个列表上下文。您正在为数组的元素分配多个单词。发生 split+glob 。

export还要注意某些 shell 中的/ local/ typeset/ declare/之类的东西的双重性质readonly(更多详细信息请参见局部变量赋值需要引号吗?

你会注意到:

foo=$bar

被解析为一个赋值语句

"foo"=$bar

只是尝试运行该foo=content_of_bar命令(其中 bar 的内容受 split+glob 影响)。

在 shell 中,其中export(and other local/ typeset...) 既是关键字又是内置命令(ksh、bash 和 zsh 的最新版本),位于:

export foo=$bar

export被认为是关键词作为foo=$bar一个赋值,so$bar不受 split+glob 的影响。但不费什么功夫export就不再被认为是关键词。在这种情况下,它只是被视为一个简单的命令,并且 split+glob 的发生就像任何其他命令的任何参数一样。

即使在export被视为关键字的情况下,如果参数看起来不像变量赋值(如上面所示"foo"=$bar),那么它们也会被视为普通参数,并再次受到 split+glob 的影响。

答案2

要回答你的两个问题,我们首先要知道什么是“安全”。 Bash 有大量的扩展,并且它们都按一定的顺序发生。通常,当我们说某样东西“安全”时,我们的意思是不会发生不情愿的分词情况。在这个意义上说:

  1. 是“安全的”,即不需要双引号。引用 bash 手册:

    可以通过以下形式的语句将变量赋值给

              name=[value]
    

    如果未给出值,则为该变量分配空字符串。所有的值都会经历波形符扩展、参数和变量扩展、命令替换、算术扩展和引号删除(请参阅下面的扩展)

    请注意,不执行分词!因此,从这方面来说,它是相当安全的,执行bar="rm asdf"; foo=$bar;不会导致任何疯狂的事情,比如执行失败,甚至你的文件被删除,或者$fooeval $foo。然而,什么将要发生的是变量扩展:

    foo="Tomatoes are $50"将导致foo拥有内容Tomatoes are 0。这可能是也可能不是您想要的。

  2. 以类似的方式工作: foo="rm asdf"; export bar=$foo不会删除您的文件并且会正确解析,并且foo="rm asdf"; array=($foo)也会解析。请注意,在数组的情况下,实际上是分词发生,所以 的第一个元素array将是rm

    此外,您仍然会获得这两个扩展中的其他扩展。我也相当肯定在这种export情况下会发生单词分割,只是导出接受所有单词作为参数并以您期望的方式解析它,类似于echo $foo不需要引号的方式。

在所有这些例子中,我认为数组示例是最不安全的一个,因为分词确实会发生并且具有具体的效果。因此,在这种情况下您将需要双引号。

相关内容