这里的文档和POSIX shell

时间:2015-12-08 14:13:54

标签: posix sh

以下文本在POSIX模式下通过两个Unix shell接受不同的处理:

readonly a=$(cat - <<'EOF'
1st
2nd
EOF
)

一个shell( bash(1) --posix)使$a拥有&#34;第一个第二个&#34;而另一个拒绝,说

  

破折号:1:只读:第二名:错误的变量名称

一旦readonly被删除,两个shell都会同意,即当a是分配给RHS的新变量时。

其中一个炮弹比另一个更正确吗?

使用任一shell,我可以先分配a,然后将其标记为readonly,这样就有了解决方案。但是,当移植到 dash(1)(版本0.5.7-4ubuntu1)时,重写似乎是必需的。这是破折号中的错误吗?

更新:从chepner的答案(单词,引语)中学习,似乎值得一提的是沿途找到的一些问题。因此,

readonly a=$*             ; echo a $a
b=$*         ; readonly b ; echo b $b
readonly c="$*"           ; echo c $c

在所有 bash dash posh zsh 中产生不同的行为,包括依赖于文本的错误在$*。通过测试交换readonly local时的类似问题。

1 个答案:

答案 0 :(得分:1)

TL; DR这可能是未定义行为的情况,其中shell可以将name=value参数readonly视为真正的赋值语句或常规字符串参数。这将影响对字符值进行分词的方式。

我认为这是dash正确的情况。在正常的分配中,例如

a=$(cat - <<'EOF'
1st
2nd
EOF
)

右侧不受分词限制。命令替换的结果是一个包含两个嵌入换行符的字符串,该换行符将分配给变量。

然而,

readonly本身就是一个命令; name=value语法是普通参数,而不是赋值语句,因此需要进行分词。命令替换产生一个带有嵌入换行符的字符串,但由于它没有引用,因此这些换行符被视为任意空格。结果相当于

readonly a=1st 2nd

显然是错误的。正如您所料,如果引用命令替换(保护换行符),则会得到预期的赋值:

readonly a="$(cat - <<'EOF'
1st
2nd
EOF
)"

zsh产生与dash相同的错误:

% readonly a=$(cat - <<'EOF'
cmdsubst heredoc> 1st
cmdsubst heredoc> 2nd
cmdsubst heredoc> EOF
cmdsubst> )
readonly: not an identifier: 2nd
192%

bashksh表现出相同的行为。 bash手册页没有提供任何关于为什么不需要引用的提示,尽管ksh手册页确实提到了readonly作为真正赋值的参数(强调矿):

  

变量分配。

     

一个或多个变量赋值可以启动简单命令,也可以启动          typeset,enum,export或readonly 特殊内置参数          命令