以下文本在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
时的类似问题。
答案 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%
bash
和ksh
表现出相同的行为。 bash
手册页没有提供任何关于为什么不需要引用的提示,尽管ksh
手册页确实提到了readonly
作为真正赋值的参数(强调矿):
变量分配。
一个或多个变量赋值可以启动简单命令,也可以启动 typeset,enum,export或readonly 特殊内置参数 命令