为什么在shell中的赋值语句中展开参数后不会发生字段拆分?

为什么在shell中的赋值语句中展开参数后不会发生字段拆分?,shell,posix,variable-assignment,Shell,Posix,Variable Assignment,考虑以下两个任务 $ a="foo bar" $ b=$a $ b=foo bar bash: bar: command not found 为什么第二个作业很好?第二个命令与第三个命令有何不同 我希望第二次作业失败,因为 b=$a 将扩展到 b=foo bar 由于$a不在双引号内,foo bar不被引用,因此应发生字段拆分(根据我的理解),这将导致b=foo被视为赋值,而bar是找不到的命令 小结:我原以为第二个命令会失败,原因与导致第三个命令失败的原因相同。为什么第二个命令成功

考虑以下两个任务

$ a="foo  bar"
$ b=$a
$ b=foo  bar
bash: bar: command not found
为什么第二个作业很好?第二个命令与第三个命令有何不同

我希望第二次作业失败,因为

b=$a
将扩展到

b=foo  bar
由于
$a
不在双引号内,
foo bar
不被引用,因此应发生字段拆分(根据我的理解),这将导致
b=foo
被视为赋值,而
bar
是找不到的命令

小结:我原以为第二个命令会失败,原因与导致第三个命令失败的原因相同。为什么第二个命令成功了

我查看了,但找不到任何指定在赋值中发生参数扩展后不会发生字段拆分的内容

我的意思是,在参数展开后,对于一个不带引号的参数,在任何其他地方都会发生字段拆分。比如说,

$ a="foo  bar"
$ printf "[%s] [%s]\n" $a
[foo] [bar]

在参数扩展(参数扩展)、命令替换(命令替换)和算术扩展(算术扩展)之后,shell应扫描扩展和替换的结果,这些扩展和替换没有出现在双引号中,用于字段拆分,并且可能会产生多个字段

那么POSIX标准的哪一部分在赋值语句中发生参数扩展时防止字段拆分呢?

在2.9.1“简单命令”中:

根据Shell语法规则被识别为变量赋值或重定向的单词将保存起来,以便在步骤3和4中进行处理

步骤2——在本例中根据上述文本明确跳过——重申在执行扩展和字段拆分时忽略赋值:

非变量赋值或重定向的单词应展开。如果展开后仍有任何字段,则第一个字段应视为命令名,其余字段为命令的参数

因此,第2步确定要运行的命令(基于变量赋值和重定向以外的内容),它解决了问题中给出的
b=$a
案例


步骤4对赋值执行其他扩展——“波浪线扩展、参数扩展、命令替换、算术扩展和引号删除”。值得注意的是,字段拆分不是此集合的成员。事实上,在2.6中明确指出,所有这些都不会在其自身中产生多个单词:

在单个单词中发生的波浪形展开、参数展开、命令替换、算术展开和引号删除扩展到单个字段只有字段拆分或路径名扩展才能从一个单词创建多个字段。此规则的唯一例外是在双引号内扩展特殊参数“@”,如特殊参数中所述


你为什么会“希望”这种行为?这会使语言更难正确使用。@CharlesDuffy我不希望有这种行为。我试图了解标准是如何规定当前行为的。虽然我不太清楚为什么您认为其他行为(赋值中参数扩展后的字段拆分)会使语言更难使用。我们已经习惯于引用参数扩展,例如
ls“$foo”
。在赋值中,这样做也不是特别困难,例如,代码> B=“$A”/代码>。顺便说一下,虽然已经有了几次修改,但我现在认为我的答案已经完成了。赋值的右边是一个单词,因此不会发生拆分。构成单个单词上下文的内容可能很微妙,看看你是否想要一个详细的概述。收藏:在
a=$b
的情况下,单词到底是什么?整个
a=$b
是否被视为一个单词?或者
a
是一个单词而
$b
是另一个单词?这就是为什么
=
周围不能有空格的原因,因为它必须是一个单词。我认为最后一句话(
只有字段拆分或路径名扩展才能从一个单词创建多个字段
)与此问题无关。例如,在
ls$a
中,
$a
可能会创建多个字段,因为
$a
没有被引用,因此在展开
$a
后会发生字段拆分。因此,尽管您在最后引用了一些内容,但对于
a=$b
也可能会发生字段拆分。这就是为什么我认为最后一句话是不相关的。但您引用的其他部分是相关的,但没有一部分明确禁止为分配而拆分字段。