这里的文档和 POSIX shell 中的只读标志和命令替换
here document and the readonly flag and command substitution in POSIX shells
以下文本在 POSIX 模式下受到两个 Unix shells 的不同处理:
readonly a=$(cat - <<'EOF'
1st
2nd
EOF
)
一个shell (bash(1) --posix) 使得$a
有“1st 2nd”而另一个拒绝,说
dash: 1: readonly: 2nd: bad variable name
一旦 readonly
被删除,即当 a
是分配给 RHS 的新变量时,shell 就一致。
其中一个 shell 比另一个更正确吗?
使用shell,我可以先赋值a
,然后标记readonly
,这样就有解决办法了。尽管如此,当移植到 dash(1)(版本 0.5.7-4ubuntu1)时,重写似乎是一个要求。这是 dash 中的错误吗?
更新:从chepner的回答(文字,引用)中学习,似乎值得一提的是在此过程中发现的一些问题。因此,
readonly a=$* ; echo a $a
b=$* ; readonly b ; echo b $b
readonly c="$*" ; echo c $c
在所有 bash、dash、posh 中产生不同的行为, zsh, 包括根据 $*
中文本的错误。通过测试将 readonly
换成 local
时出现类似问题。
TL;DR 这可能是未定义行为的情况,其中 shell 可以自由地将 readonly
的 name=value
参数视为真正的赋值语句或常规字符串参数。这将影响分词应用于值的方式。
我认为这是 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
的参数是一个真正的赋值(强调我的):
Variable Assignments.
One or more variable assignments can start a simple command or can be
arguments to the typeset, enum, export, or readonly special built-in
commands
以下文本在 POSIX 模式下受到两个 Unix shells 的不同处理:
readonly a=$(cat - <<'EOF'
1st
2nd
EOF
)
一个shell (bash(1) --posix) 使得$a
有“1st 2nd”而另一个拒绝,说
dash: 1: readonly: 2nd: bad variable name
一旦 readonly
被删除,即当 a
是分配给 RHS 的新变量时,shell 就一致。
其中一个 shell 比另一个更正确吗?
使用shell,我可以先赋值a
,然后标记readonly
,这样就有解决办法了。尽管如此,当移植到 dash(1)(版本 0.5.7-4ubuntu1)时,重写似乎是一个要求。这是 dash 中的错误吗?
更新:从chepner的回答(文字,引用)中学习,似乎值得一提的是在此过程中发现的一些问题。因此,
readonly a=$* ; echo a $a
b=$* ; readonly b ; echo b $b
readonly c="$*" ; echo c $c
在所有 bash、dash、posh 中产生不同的行为, zsh, 包括根据 $*
中文本的错误。通过测试将 readonly
换成 local
时出现类似问题。
TL;DR 这可能是未定义行为的情况,其中 shell 可以自由地将 readonly
的 name=value
参数视为真正的赋值语句或常规字符串参数。这将影响分词应用于值的方式。
我认为这是 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
的参数是一个真正的赋值(强调我的):
Variable Assignments.
One or more variable assignments can start a simple command or can be arguments to the typeset, enum, export, or readonly special built-in commands