POSIX shell:如果`$` 是单词中的最后一个字符,它会失去它的特殊含义吗?

Har*_*her 17 shell posix

在 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,!$可以调用历史扩展(前一个命令的最后一个参数)。所以总的来说,不,$在未引用的词的末尾不是没有意义,但在词的末尾它至少不表示标准扩展。


Mic*_*mer 7

根据具体情况,这不是明确指定的(因此实现可能会按照他们的意愿进行)或需要按照您的观察发生。在您的确切场景中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>

结果是不确定的。

“未指定”在这里是一个特殊术语,意思是

  1. 在这种情况下,符合标准的外壳可以选择任何行为
  2. 符合要求的应用程序不能依赖于任何特定的行为

在您的示例中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作为参数的一部分传递给命令。这是对外壳的一致性要求。