Kus*_*nda 7 bash ksh function variable typeset
我正在编写一组希望在 Bash 和 KornShell93 中使用的 shell 函数,但是使用 Bash 我遇到了“循环名称引用”警告。
这是问题的本质:
function set_it {
typeset -n var="$1"
var="hello:$var"
}
function call_it {
typeset -n var="$1"
set_it var
}
something="boff"
call_it something
echo "$something"
Run Code Online (Sandbox Code Playgroud)
运行它:
$ ksh script.sh
hello:boff
$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:
Run Code Online (Sandbox Code Playgroud)
KornShell93 完全符合我的要求,但是 Bash 失败了,并且如果something脚本中的变量被命名,还会在第 2 行警告同样的事情var。
我希望var变量是每个函数的局部变量,这就是我使用 的原因typeset,但 Bash 似乎不喜欢将 nameref “取消引用”到与 nameref 本身同名的变量。我不能使用,local -n或者declare -n因为它会在ksh缺少这些的情况下破裂,即使我这样做了,也不能解决问题。
我发现的唯一解决方案是在每个函数中使用唯一的变量名,这看起来很愚蠢,因为它们是本地的。
Bash 手册说明了以下内容typeset:
typeset[...]
-n为每个名称赋予nameref属性,使其成为对另一个变量的名称引用。另一个变量由 的值定义name。对 的所有引用和赋值name,除了更改-n属性本身,都是在名称的值引用的变量上执行的。[...]
当在功能使用的,
declare并且typeset使每个本地名称,与local命令,除非-g选项被提供。如果变量名后跟=value,则变量的值设置为value。
很明显,我对 Bash 的名称引用和函数局部变量有些不理解。
所以,问题是:在这种情况下,我是否遗漏了有关 Bash 处理名称引用变量的内容,或者这是 Bash 中的错误/错误功能?
更新:我目前正在GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)与GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0). macOS 附带的 Bash 太旧了,根本不知道名称引用。
更新:更短:
function bug {
typeset -n var="$1"
printf "%s\n" "$var"
}
var="hello"
bug var
Run Code Online (Sandbox Code Playgroud)
结果在bash: warning: var: circular name reference. 该var函数中应该有不同的范围从var在全球范围内。这对调用者施加了不必要的限制。限制是“您不能随意命名变量,因为在此函数中可能会与(本地)nameref 发生名称冲突”。
Chet Ramey(Bash 维护者)说
今年早些时候,bug-bash 上对 namerefs 进行了广泛的讨论。我对如何改变这种行为有一个合理的建议,我将在 bash-4.4 发布后查看它。
与此同时,我稍微混淆了本地 nameref 变量的名称,这样它们就不会在库内发生冲突,也不会(希望)与全局 shell 变量名称发生冲突。
在bash5.0 中,这个问题得到了轻微的补救(但没有真正修复)。以下是观察到的行为:
$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello
Run Code Online (Sandbox Code Playgroud)
这表明它有效,但也有一些警告。
相关新闻条目说
Run Code Online (Sandbox Code Playgroud)i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.