从 POSIX 7 开始:
单词扩展的顺序如下:
波形符扩展(参见第 2.6.1 节)、参数扩展(参见第 2.6.2 节)、命令替换(参见第 2.6.3 节)和算术扩展(参见第 2.6.4 节)应从头到尾执行。请参阅第 2.3 节中的第 5 项。
除非 IFS 为空,否则应对步骤 1 生成的字段部分执行字段拆分(参见第 2.6.5 节)。
除非 set -f 有效,否则应执行路径名扩展(参见第 2.6.6 节)。
报价删除(参见第 2.6.7 节)应始终最后执行。
波形符扩展、参数扩展、命令替换和算术扩展是否按指定顺序执行?
它们之间的顺序重要吗?如果是,我们如何理解为什么顺序是这样的?
为什么路径名扩展发生在字段分割之后,而其他扩展发生在字段分割之前?
特别是,波浪号扩展和路径名扩展都与路径名和文件名有关,为什么它们在字段分割方面的放置方式不同?
POSIX 中没有大括号扩展吗?
我注意到“单词扩展”。扩展是否仅适用于具有令牌标识符 WORD 的令牌,而不适用于具有其他令牌标识符(例如 NAME、特定运算符、NEWLINE、IO_NUMBER、ASSIGNMENT)的令牌?
答案1
波形符扩展、参数扩展、命令替换和算术扩展列在同一步骤中。这意味着它们被执行同时。波形符扩展的结果不进行参数扩展,参数扩展的结果不进行波形符扩展,等等。例如,如果 的值为foo
,$(bar) qux
则该单词在步骤 1 处$foo
扩展为;$(bar) qux
参数扩展产生的文本不会在步骤 1 中进行任何进一步的转换,但随后会被步骤 2 分割。
“开始到结束”意味着从左到右的处理,这很重要,例如当发生赋值时:a=1; echo $a$((a=2))$a
打印,因为在第一个参数扩展和第二个参数扩展之间执行122
算术扩展,设置为2 。$((a=2))
a
$a
$a
该顺序的原因是历史使用情况。 POSIX 通常遵循现有的实现,很少指定新的行为。周围有多个贝壳;在大多数情况下,POSIX 遵循科恩壳但省略了大多数不存在的功能伯恩外壳(由于 Bourne shell 基本上已被废弃,因此 POSIX 的下一版本可能会包含新的 ksh 功能)。
Bourne shell 执行参数扩展、字段分割、通配符的原因是它允许将通配符存储在变量中:您可以设置a
to *.txt *.pdf
,然后使用$a
代表匹配的文件名列表*.txt
,后跟名称列表匹配*.pdf
(假设两个模式匹配)。 (我并不是说这是最好的设计,只是说它就是这样设计的。)我不太清楚为什么人们希望将命令替换放置在 Bourne shell 的特定步骤中;在 Korn shell 中,其语法$(…)
接近于参数扩展,${…}
因此将它们一起执行是有意义的。
波形符扩展的位置是一个历史怪事。稍后放置它会更有意义,这样您就可以编写~$some_user
并将其扩展到名称为变量值的用户的主目录some_user
。我不知道为什么不这样做。这个命令甚至需要一个特殊的声明,即波浪号扩展的结果不会进行其他扩展(根据您引用的段落,如果HOME
是/foo bar
则那么~
将扩展为两个单词/foo
和bar
由于字段分割,但没有 shell 这样做,并且 POSIX.2008明确指出“由波形符扩展产生的路径名应被视为带引号”)。
POSIX 中没有大括号扩展,否则规范会说明这一点。
单词扩展仅在 WORD 上执行,并在以下部分中提到注意事项(例如,字段分割和路径名生成仅在允许多个单词的上下文中执行,例如在双引号之间不执行)。 NAME、NEWLINE、IO_NUMBER 等不包含任何可以扩展的内容。
答案2
关于(1),该顺序基于现有实施。如果参与编写的人知道不同 shell 的不同顺序被认为是标准,他们会在措辞中提供一些余地以允许这样做。如中所述2.6 词扩展,没有任何迹象表明其他订购可以符合该标准。
再次,对于 (2),请记住这是基于现有的实现。最初实施的原因不一定能在标准中找到,尽管对于一些有趣的分歧领域(例如,BSD 与 SVr4),理由本节总结了委员会选择其中一个相互冲突的替代方案的原因。
对于(3),你提到的“大括号扩展”可能与2.6.2 参数扩展(尽管还有其他可能性,但不一定在 POSIX 中)。
最后(4),记起那一个NAME
是某种类型的WORD
。词扩展适用于名字。
答案3
- 前四个扩展顺序:
每个扩展的触发器都是不同的:波形符扩展~
、参数扩展$name
和${name}
、命令替换$()
和` `
以及算术扩展$((...)))
。因此,顺序并不重要,因为无法将一个扩展与另一个混淆,并且每个扩展仅执行一次。已进行参数扩展的令牌将不会进行命令替换(例如)。
一种可能令人困惑的扩展是算术扩展,因为(在其内部)可能存在参数扩展、扩展、字符串扩展、命令替换和引号删除。并且,算术扩展可以嵌套。但所有这些都发生在已经检测到的算术展开式内部,而不是外部。
最重要的顺序是从左到右。
毕竟,上述扩展的结果(如果没有引用)将受到字段分割和路径名扩展(按顺序)的影响。
所有扩展最终都将被删除报价。
- 不,POSIX 中没有大括号扩展。
- 在这种情况下,单词和标记通常表示相同的想法。