在 ash、dash 和 bash 上,当我跑步时
$ echo ab$
Run Code Online (Sandbox Code Playgroud)
它返回
ab$
Run Code Online (Sandbox Code Playgroud)
这种行为是由 POSIX 指定的还是只是符合 POSIX 的 shell 中的常见约定?我在 POSIX Shell 命令语言页面上找不到任何提到此行为的内容。
Kus*_*nda 10
$
本身没有特殊含义(try echo $
),只有在与它后面的其他字符组合并形成扩展时才具有特殊含义,例如$var
(或${var}
)$(util)
,,$((1+2))
。
在$
得到其“特殊”的含义定义在章节POSIX标准的扩展标志物辨别:
如果当前字符是未加引号的
$
or`
,shell 应从它们的介绍性未加引号的字符序列中识别参数扩展、命令替换或算术扩展的任何候选的开始:$
或${
、$(
或`
、 和$((
。shell 应读取足够的输入以确定要扩展的单元的结尾(如引用的部分中所述)。在处理字符时,如果发现扩展或引用的实例嵌套在替换中,shell 应以为找到的构造指定的方式递归处理它们。从替换开始到结束发现的字符,允许识别嵌入构造所需的任何递归,应包括在结果标记中未经修改,包括任何嵌入或封闭的替换运算符或引号。代换结束时,令牌不应被定界。
因此,如果$
不形成扩展,则其他解析规则生效:
如果前一个字符是单词的一部分,则当前字符应附加到该单词后。
这涵盖了你的ab$
字符串。
在一个人的情况下$
(“新词”$
本身就是这个词):
当前字符用作新单词的开头。
包含非标准扩展的生成词的含义$
被 POSIX 明确定义为未指定。
另请注意,这$
是 中的最后一个字符$$
,但这也恰好是保存当前外壳程序 PID 的变量。在bash
,!$
可以调用历史扩展(前一个命令的最后一个参数)。所以总的来说,不,$
在未引用的词的末尾不是没有意义,但在词的末尾它至少不表示标准扩展。
根据具体情况,这不是明确指定的(因此实现可能会按照他们的意愿进行)或需要按照您的观察发生。在您的确切场景中echo ab$
,POSIX 强制要求您观察到的输出“ab$”并且它不是未指定的。所有不同案例的快速总结在最后。
有两个要素:首先标记为单词,然后对这些单词进行解释。
POSIX断词要求一个$
是不是一个有效的起始参数扩展,命令替换,或算术取代被认为是的文本部分WORD
构造令牌之中。这是因为规则 5(“如果当前字符是不带引号的$
or `
,shell 应从它们的介绍性不带引号的字符序列中识别参数扩展、命令替换或算术扩展的任何候选的开始:$
or ${
,$(
or `
, and $((
,分别“ ) 不适用,因为这些扩展在那里都不可行。参数扩展需要一个有效的名称出现在那里,空名称是无效的。
由于此规则不适用,我们继续遵循,直到找到适用的规则。两个候选是 #8(“如果前一个字符是单词的一部分,则当前字符应附加到该单词。”)和 #10(“当前字符用作新单词的开头。”) ,分别适用于echo a$
和echo $
。
还有第三种情况echo a$+b
,因为+
它不是特殊参数的名称。这个我们稍后会回到,因为它触发了规则的不同部分。
因此,规范要求在$
语法上将其视为单词的一部分,然后可以在以后进一步处理。
在以这种方式解析输入后$
,将单词包含在单词中,单词扩展将应用于已阅读的每个单词。每个单词都是单独处理的。
规定:
如果未加引号的 '$' 后跟不是以下字符之一:
- 一个数字字符
- 特殊参数之一的名称(请参阅特殊参数)
- 变量名的有效第一个字符
- 一个
<left-curly-bracket>
('{')- 一种
<left-parenthesis>
结果是不确定的。
“未指定”在这里是一个特殊术语,意思是
在您的示例中echo ab$
, the$
后面没有任何字符,因此此规则不适用并且不会调用未指定的结果。根本没有由 激发的扩展$
,因此它确实存在并打印出来。
它会应用在我们的第三种情况从上面:echo a$+b
。这里$
后面是+
,这不是数字,特殊参数(@
,*
,#
,?
,-
,$
,!
,或0
),启动一可变的名称(下划线或从字母便携式字符集),或支架中的一个。在这种情况下,行为是未指定的:符合标准的 shell被允许发明一个称为+
expand的特殊参数,并且符合标准的应用程序不应假设 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
作为参数的一部分传递给命令。这是对外壳的一致性要求。