当我跑步时,在灰烬、冲刺和猛击上
$ echo ab$
它返回
ab$
此行为是 POSIX 指定的还是只是 POSIX 兼容 shell 中的常见约定?我在 POSIX Shell 命令语言页面上找不到任何提及此行为的内容。
答案1
$
本身并没有特殊含义(try echo $
),只有与其后的其他字符组合形成扩展时才有特殊含义,例如$var
(或${var}
)$(util)
,,$((1+2))
。
其$
“特殊”含义是在 POSIX 标准中定义扩展 部分令牌识别:
如果当前字符是不带引号的
$
or`
,则 shell 应从其介绍性不带引号的字符序列中识别参数扩展、命令替换或算术扩展的任何候选者的开始:$
or${
、$(
or`
、 and$((
。 shell 应读取足够的输入以确定要扩展的单元的末尾(正如所引用的章节中所解释的)。在处理字符时,如果在替换中发现嵌套的扩展或引用实例,则 shell 应按照为找到的构造指定的方式递归处理它们。从替换开始到结束找到的字符(允许识别嵌入结构所需的任何递归)应不加修改地包含在结果标记中,包括任何嵌入或封闭的替换运算符或引号。令牌不应由替换结束时界定。
所以,如果$
不形成扩展,则其他解析规则生效:
如果前一个字符是单词的一部分,则当前字符应附加到该单词后。
那覆盖了你的ab$
字符串。
在单独的情况下$
(“新词”$
本身就是 the):
当前字符用作新单词的开头。
这意义$
包含非标准扩展的生成单词的被 POSIX 明确定义为未指定。
另请注意$
是 中的最后一个字符$$
,但这也恰好是保存当前 shell PID 的变量。在 中bash
,!$
可以调用历史扩展(上一个命令的最后一个参数)。所以一般来说,no,$
在未引用的单词末尾并不是没有意义,但在单词末尾它至少不表示标准扩展。
答案2
根据具体情况,这要么是明确未指定的(因此实现可能会按照它们的意愿进行),要么需要按照您观察到的方式发生。在你的具体场景中echo ab$
,POSIX 强制输出您观察到的“ab$”和这不是未指定的。最后对所有不同案例进行了快速总结。
有两个要素:首先将其标记为单词,然后解释这些单词。
代币化
POSIX 标记化要求A$
不是有效的开始参数扩展,命令替换, 或者算术替换被视为WORD
正在构建的令牌的字面部分。这是因为规则 5(“如果当前字符是不带引号的$
or `
,则 shell 应从其介绍性不带引号的字符序列中识别参数扩展、命令替换或算术扩展的任何候选者的开始:分别为$
or ${
、$(
or `
、 和$((
” )不适用,因为这些扩展在那里都不可行。参数扩展需要一个有效的名称出现在那里,空名称是无效的。
由于这条规则不适用,我们将继续遵循,直到找到一条适用的规则。两个候选者是#8(“如果前一个字符是单词的一部分,则当前字符应附加到该单词。”)和#10(“当前字符用作新单词的开头。”) ,分别适用于echo a$
和echo $
。
还有第三种形式的情况也echo a$+b
属于同样的情况,因为+
不是特殊参数的名称。我们稍后会再讨论这一点,因为它会触发规则的不同部分。
因此,规范要求从$
语法上将其视为单词的一部分,然后可以在以后对其进行进一步处理。
单词扩展
以这种方式解析输入并$
包含在单词中后,单词扩展应用于已读过的每个单词。每个单词都经过处理单独地。
明确规定:
如果未加引号的“$”后跟的字符不是以下字符之一:
- 一个数字字符
- 特殊参数之一的名称(参见特殊参数)
- 变量名的有效第一个字符
- A
<left-curly-bracket>
( '{' )- A
<left-parenthesis>
结果未指定。
“未指定”是这里的一个特殊术语,意思是
- 在这种情况下,一致的 shell 可以选择任何行为
- 一个合格的应用不能依赖任何特定行为
在您的示例中echo ab$
,$
后面没有任何特点,因此该规则不适用,并且不会调用未指定的结果。根本没有引起任何扩展$
,因此它确实存在并打印出来。
在哪里会apply 在我们上面的第三个案例中是:echo a$+b
。后面$
跟着+
,它不是数字,特殊参数(@
,*
,#
,?
,-
,$
,!
或0
),变量的开头姓名(下划线或字母便携式字符集),或括号之一。在这种情况下,行为未指定:一致的 shell被允许发明一个称为+
展开的特殊参数,以及符合要求的应用程序不应该假设 shell 不。 shell 还可以做任何它喜欢做的事情,包括报告错误。
例如,zsh,包括其 POSIX 模式,解释$+b
为“是变量b
集”并用 1 或 0 代替它的位置。它同样具有~
和的扩展=
。这是顺应行为。
另一个可能发生这种情况的地方是echo "a$ b"
。同样,shell 可以按照自己的意愿行事,并且作为脚本作者,$
如果您想要文字输出,则应该转义 。如果你不这样做,它可能会起作用,但你不能依赖它。这是规范的绝对字母,但我不认为这种粒度是有意或考虑的。
总之
echo ab$
:文字输出,完全指定echo a$ b
:文字输出,完全指定echo a$ b$
:文字输出,完全指定echo a$b
:参数扩展b
,完全指定echo a$-b
:特殊参数扩展-
,完全指定echo a$+b
:未指定的行为echo "a$ b"
:未指定的行为
对于$
单词末尾的 a,您可以依赖该行为,并且必须按字面意思对其进行处理,并将其echo
作为其参数的一部分传递给命令。这是对外壳的一致性要求。