首先,我知道使用function
关键字与myfunction()
声明函数时bash和ksh之间的一般范围差异(动态/静态),此帖仅讨论了范围问题只读变量。
今天我偶然发现了令我困惑的事情。我有一个脚本从使用function
关键字声明的函数中获取文件(因此我没有立即知道为什么会发生以下情况,因为我通过&#34查看了这些单独的文件; global-范围护目镜")。
作为最近清理的一部分,我在这些源文件中只读取了各种变量,并注意到代码的某些部分在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都有):
readonly foo=function
将'function'
分配给全局变量foo
,并且不声明新的局部变量(与[4]相同)typeset -r bar=function
将'function'
分配给新的本地变量bar
(与[3]相同)typeset baz=function; readonly baz
将'function'
分配给新的本地变量baz
(与[2]相同)qux=function; readonly qux
将'function'
分配给全局变量qux
,并且不声明新的局部变量(与[1]相同)。 qux
只在本地和全局范围内都是只读的,但这是预期的,因为它将全局变量标记为只读,并且由于动态范围,它在函数中也变为只读(旁注:see also )。quux=function; typeset -r quux
将'function'
分配给全局变量quux
,然后声明一个没有值的新局部变量quux
readonly
从不声明新的(本地)变量(如预期的那样)。对于[1]和[4],它只读取全局变量,对于[3]新的局部变量。这完全是我所期望的,意味着readonly
操作的范围与相应变量本身的范围相同,即
x=y
;如果$x
是本地的,则readonly x
会标记本地变量x
readonly x=y
;如果$x
是全局的,那么readonly x
会标记全局变量x
readonly 分别为[1] / [2]和[4] / [5]之间的一致性
(讨论f; g的行为与预期一致):
readonly foo=function
:类似于[5],[8]和[9],但更令人困惑,因为这是一个命令(相反于:赋值优先,readonly
/ { {1}}之后)。显然,typeset -r
声明了一个没有值的新局部变量readonly
,但将全局变量foo
设置为foo
。 ?!。 'function'
在功能和全局范围内都是只读的。foo
将typeset -r bar=function
分配给新的本地变量'function'
(与[8]相同)bar
将typeset baz=function; readonly baz
分配给新的本地变量'function'
(与[7]相同)。 baz
仅在函数范围内变为只读baz
将qux=function; readonly qux
分配给全局变量'function'
,然后声明一个没有值的新局部变量qux
(与[5],[6]相同) ,[10])。 qux
仅在函数范围内变为只读qux
将quux=function; typeset -r quux
分配给全局变量'function'
,然后声明一个没有值的新局部变量quux
(与[5],[9]相同) ,[10])。 quux
仅在函数范围内变为只读。quux
似乎确实在[6]和[9]中声明了新的局部变量,但在[8]中却没有。预计bash的行为。 readonly
(= typeset
)在函数范围内创建/修改(bash具有declare
选项以强制在全局范围内创建/修改,即使在函数内部使用时),{{1真的只有"标记"现有变量,永远不会引入新的局部变量。 [5]我有点困惑,因为我以前从来没有必要声明一个未设置的只读变量,我会假设如果存在一个同名的全局变量,它会修改它,但我绝对可以忍受这种行为,因为它是一致的与其他场景和-g
的存在。
但是,根据我的理解,ksh手册页未能完全解释上述所有场景以及readonly
和-g
关键字之间的细微差别,除非我在重读时忽略了某些内容问题各节。
对我来说最让人困惑的是,它在readonly
和typeset -r
之间的范围差异解释附近提到关键字readonly
,以及foo()
的简短说明inbuilt也没有提到这一点。基于此,我永远不会假设function bar
引入了新的,静态范围的变量,如readonly
,并且在某些(但不是所有)场景中它确实出乎意料。
对我来说最令人困惑的情况是[6]并且我无法理解那里到底发生了什么(这也是破坏我的代码的具体方案)。
我的观察是否正确,是否有人可以了解ksh93的行为? (我希望这个问题是可接受的范围(没有双关语意))
答案 0 :(得分:1)
欢迎来到shell不兼容的世界:)
如果我正确理解了这个问题,那就是
之间的区别功能blah {}
和
blah(){}
看广告人ksh(1)(在Solaris上,如果有任何区别的话)
Functions defined by the function name syntax and called by
name execute in the same process as the caller and share all
files and present working directory with the caller.
...
Ordinarily, variables
are shared between the calling program and the function.
However, the typeset special built-in command used within a
function defines local variables whose scope includes the
current function. They can be passed to functions that they
与
Functions defined with the name() syntax and functions
defined with the function name syntax that are invoked with
the . special built-in are executed in the caller's environ-
ment and share all variables and traps with the caller.
Errors within these function executions cause the script
that contains them to abort.
答案 1 :(得分:1)
错误如下,当您不使用"local"
或将函数设为子shell时,函数没有“本地”范围!
因此,请使用f() ( <code> )
代替f() { <code> }
来获取您的本地范围!
仍然,你有一点!
"readonly <var>"
和"declare -r <var>"
之间的区别!
# ./readonly_test.sh
bash: 3.00.16(1)-release
inside function
----------------
foo=function
bar=function
baz=function
qux=function
quux=
global scope after calling
----------------------------
foo=global
bar=global
baz=global
qux=global
quux=global