function首先,在使用关键字 vs.声明函数时,我知道 bash 和 ksh 之间的一般范围界定差异(动态/静态),myfunction()并且这篇文章仅讨论有关只读变量的范围界定问题。
不过,今天我偶然发现了一些让我感到困惑的事情。我有一个脚本,它从使用关键字声明的函数中获取文件function(因此,当我通过“全局范围护目镜”查看这些单独的文件时,我并没有立即意识到为什么会发生以下情况)。作为最近清理的一部分,我将这些源文件中的各种变量设置为只读,并注意到代码的某些部分在 ksh93 下停止工作,这取决于我如何将变量标记为只读。更具体地说,如果我使用readonly FOO=bar,${FOO}将对源文件的其余部分取消设置。
这说明了问题:
(注意:内联代码的行为是相同的(与获取源代码的第二个脚本相比),但由于它在这里保存了一些行并且帖子已经很长了,所以我保持原样)
readonly_test_sourced.sh:
readonly foo=function
typeset -r bar=function
typeset baz=function
readonly baz
qux=function
readonly qux
quux=function
typeset -r quux
readonly_test.sh:
function f
{
. ./readonly_test_sourced.sh
printf "foo=${foo}\nbar=${bar}\nbaz=${baz}\nqux=${qux}\nquux=${quux}\n"
}
g()
{
. ./readonly_test_sourced.sh
printf "foo=${foo}\nbar=${bar}\nbaz=${baz}\nqux=${qux}\nquux=${quux}\n"
}
[ -n "${KSH_VERSION}" ] && echo "ksh: ${KSH_VERSION}"
[ -n "${BASH_VERSION}" ] && echo "bash: ${BASH_VERSION}"
for var in foo bar baz qux quux; do
unset "${var}"
eval "$var=global" # don't do this at home, there are better ways
done
func="${1:-f}"
echo
echo "inside function ${func}"
echo '----------------'
${func}
echo
echo "global scope after calling ${func}"
echo '----------------------------'
printf "foo=${foo}\nbar=${bar}\nbaz=${baz}\nqux=${qux}\nquux=${quux}\n"
这是我使用 ksh93u+ 得到的输出:
$ ksh ./readonly_test.sh f
ksh: Version JM 93u+ 2012-02-29
inside function f
----------------
foo=
bar=function
baz=function
qux=
quux=
global scope after calling f
----------------------------
foo=function
bar=global
baz=global
qux=function
quux=function
$ ksh ./readonly_test.sh g
ksh: Version JM 93u+ 2012-02-29
inside function g
----------------
foo=function
bar=function
baz=function
qux=function
quux=function
global scope after calling g
----------------------------
foo=function
bar=function
baz=function
qux=function
quux=function
这就是我在 bash 4.2 中得到的:
$ bash ./readonly_test.sh f
bash: 4.2.42(1)-release
inside function f
----------------
foo=function
bar=function
baz=function
qux=function
quux=
global scope after calling f
----------------------------
foo=function
bar=global
baz=global
qux=function
quux=function
$ bash ./readonly_test.sh g
bash: 4.2.42(1)-release
inside function g
----------------
foo=function
bar=function
baz=function
qux=function
quux=
global scope after calling g
----------------------------
foo=function
bar=global
baz=global
qux=function
quux=function
我还通过 mksh 运行它(它根据其手册页实现动态范围,它确实产生与使用 bash 相同的结果):
$ mksh ./readonly_test.sh f
ksh: @(#)MIRBSD KSH R40 2012/03/20
inside function f
----------------
foo=function
bar=function
baz=function
qux=function
quux=
global scope after calling f
----------------------------
foo=function
bar=global
baz=global
qux=function
quux=function
$ mksh ./readonly_test.sh g
ksh: @(#)MIRBSD KSH R40 2012/03/20
inside function g
----------------
foo=function
bar=function
baz=function
qux=function
quux=
global scope after calling g
----------------------------
foo=function
bar=global
baz=global
qux=function
quux=function
观察:
readonly有时typeset -r是同义词,有时不是bash 和 mksh
有 3 种可能的不同情况(对于 f 和 g):
- [1]
readonly foo=function赋值'function'给全局变量foo,不声明新的局部变量(与 [4] 相同) - [2]
typeset -r bar=function分配'function'给新的局部变量bar(与 [3] 相同) - [3]
typeset baz=function; readonly baz分配'function'给新的局部变量baz(与 [2] 相同) - [4]
qux=function; readonly qux分配'function'给全局变量qux并且不声明新的局部变量(与 [1] 相同)。qux在本地和全局范围内都是只读的,但这是可以预期的,因为它将全局变量标记为只读,并且由于动态范围,它在函数中也变为只读(旁注:另请参见)。 - [5]
quux=function; typeset -r quux赋值'function'给全局变量quux,然后声明一个quux没有值的新局部变量
- [1]
readonly从不声明新的(局部)变量(如预期的那样)。对于 [1] 和 [4],它将全局变量标记为只读,对于 [3],它标记新的局部变量。这完全是我所期望的,这意味着readonly运行的范围与相应变量本身的范围相同,即x=y; if$xis local thenreadonly x会将局部变量标记为x只读x=y; 如果$x是全局的,那么readonly x会将全局变量标记为x只读
[1] / [2] 和 [4] / [5] 之间的一致性,分别
在 ksh 中(讨论 f;g 的行为符合预期):
- 还有3种可能的不同情况:
- [6]
readonly foo=function:类似于 [5]、[8] 和 [9],但更令人困惑,因为这是一个单一的命令(相对于:先赋值,readonly后赋值typeset -r)。显然readonly声明了一个foo没有值的新局部变量,但将全局变量设置foo为'function'. ?!?.foo在函数和全局范围内都变为只读。 - [7]
typeset -r bar=function分配'function'给新的局部变量bar(与 [8] 相同) - [8]
typeset baz=function; readonly baz分配'function'给新的局部变量baz(与 [7] 相同)。baz仅在函数范围内变为只读 - [9]
qux=function; readonly qux分配'function'给全局变量qux,然后声明一个qux没有值的新局部变量(与 [5]、[6]、[10] 相同)。qux仅在函数范围内变为只读 - [10]
quux=function; typeset -r quux分配'function'给全局变量quux,然后声明一个quux没有值的新局部变量(与 [5]、[9]、[10] 相同)。quux仅在函数范围内变为只读。
- [6]
readonly似乎在 [6] 和 [9] 中声明了新的局部变量,但在 [8] 中没有。
- 还有3种可能的不同情况:
bash 的行为是预期的。typeset(= declare) 在函数范围内创建/修改(bash 可以-g选择强制在全局范围内创建/修改,即使在函数内部使用),readonly实际上只是“标记”现有变量,从不引入新的局部变量。[5] 让我有点困惑,因为我之前从未声明过未设置的只读变量,我会假设如果存在同名的全局变量,它会修改它,但我绝对可以忍受这种行为,因为它是一致的与其他场景和存在-g。
但是,据我了解,ksh 手册页无法完全解释上述所有场景以及关键字readonly和typeset -r关键字之间的细微差别,除非我在重新阅读问题中的相应部分时遗漏了某些内容。最让我困惑的是,它在 and 之间的作用域差异的解释附近没有提到关键字,readonly并且内置的简短解释也没有提到任何关于此的内容。基于此,我永远不会假设像 do 那样引入新的、静态范围的变量,而且在某些(但不是全部)场景中这样做似乎真的出乎意料。foo()function barreadonlyreadonlytypeset -r
对我来说最令人困惑的场景是 [6],我无法理解那里到底发生了什么(这也是破坏我的代码的特定场景)。
我的观察是否正确,有人可以阐明 ksh93 的行为吗?(我希望这个问题的范围可以接受(没有双关语))