![为什么在赋值 `foo=$bar` 时不需要双引号 `$bar`?](https://linux22.com/image/10657/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%9C%A8%E8%B5%8B%E5%80%BC%20%60foo%3D%24bar%60%20%E6%97%B6%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8F%8C%E5%BC%95%E5%8F%B7%20%60%24bar%60%EF%BC%9F%20.png)
从https://unix.stackexchange.com/a/32227/674
不使用双引号是安全的主要地方是:
- 在赋值中:(但请注意,在或在数组赋值中
foo=$bar
需要双引号,例如);export "foo=$bar"
array=("$a" "$b")
$bar
这是否意味着赋值时不需要双引号foo=$bar
?为什么?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 有大量的扩展,并且它们都按一定的顺序发生。通常,当我们说某样东西“安全”时,我们的意思是不会发生不情愿的分词情况。在这个意义上说:
是“安全的”,即不需要双引号。引用 bash 手册:
可以通过以下形式的语句将变量赋值给
name=[value]
如果未给出值,则为该变量分配空字符串。所有的值都会经历波形符扩展、参数和变量扩展、命令替换、算术扩展和引号删除(请参阅下面的扩展)。
请注意,不执行分词!因此,从这方面来说,它是相当安全的,执行
bar="rm asdf"; foo=$bar;
不会导致任何疯狂的事情,比如执行失败,甚至你的文件被删除,或者$foo
会eval $foo
。然而,什么将要发生的是变量扩展:foo="Tomatoes are $50"
将导致foo
拥有内容Tomatoes are 0
。这可能是也可能不是您想要的。以类似的方式工作:
foo="rm asdf"; export bar=$foo
不会删除您的文件并且会正确解析,并且foo="rm asdf"; array=($foo)
也会解析。请注意,在数组的情况下,实际上是分词做发生,所以 的第一个元素array
将是rm
。此外,您仍然会获得这两个扩展中的其他扩展。我也相当肯定在这种
export
情况下会发生单词分割,只是导出接受所有单词作为参数并以您期望的方式解析它,类似于echo $foo
不需要引号的方式。
在所有这些例子中,我认为数组示例是最不安全的一个,因为分词确实会发生并且具有具体的效果。因此,在这种情况下您将需要双引号。