首先,我知道使用function
關鍵字function
和myfunction()
聲明函數時bash和ksh之間的一般範圍差異(動態/靜態)文章僅討論關於只讀變量的範圍界定問題。在ksh中使用'typeset -r'和'readonly'關鍵字作爲範圍異常
今天我偶然發現了一些讓我困惑的事情。我有一個腳本,它使用function
關鍵字聲明的函數來源文件(因此我根本不知道爲什麼會發生以下情況,因爲我通過「全局範圍護目鏡」查看了這些單獨的文件)。 作爲最近一次清理的一部分,我只是在這些源文件中只讀了各種變量,並注意到部分代碼在ksh93下停止工作,這取決於我如何將變量標記爲只讀。 更具體地說,如果我使用readonly FOO=bar
,${FOO}
將取消設置源文件的其餘部分。
這證明了問題(S):
(注:行爲與內嵌代碼相同(即與被採購的第二個腳本),但因爲它可以節省一些這裏的線條和後相當已久的我一直在,因爲它是)
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
在本地和全局範圍內都是隻讀的,但這是預期的,因爲它將全局變量標記爲只讀,並且由於動態範圍的限制,它在函數中變爲只讀(注:see also)。 - [5]
quux=function; typeset -r quux
分配'function'
到全局變量quux
,然後宣佈新的本地變量quux
而不值
- [1]
readonly
從未聲明瞭一個新的(局部)變量(如預期)。對於[1]和[4],它只是將全局變量標記爲[3]新的局部變量。這完全是我所期望的,並且意味着readonly
工作的範圍與相應的變量本身相同,即x=y
;如果$x
是本地,則readonly x
將標記本地變量x
只讀x=y
;如果$x
是全球然後readonly x
將標誌着全局變量x
只讀
之間的一致性[1]/[2]和[4]/[5],分別
在KSH(討論的f;克按預期運行):
- 也有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
關鍵字之間的細微差異,除非我在重新閱讀問題中的相應部分時錯過了某些內容。 我最困惑的是沒有提到關鍵字readonly
附近的解釋foo()
和function bar
之間的範圍區別的解釋,readonly
內置的簡短說明也沒有提到這一點。基於此,我永遠不會假設readonly
引入了像typeset -r
這樣的靜態範圍的新變量,它在一些(但不是所有)場景中都會這樣做。
對我來說最令人困惑的情景是[6],我不明白到底發生了什麼(這也是破壞我的代碼的特定場景)。
我的觀察是否正確,並且有人可以闡明ksh93的行爲? (我希望這個問題是可以接受的範圍的(沒有雙關語意))
稍後我會有時間仔細閱讀。與此同時,你有沒有閱讀[此線程](http://gnu-bash.2382.n7.nabble.com/inconsistency-with-quot-readonly-quot-and-scope-td5400.html#none)呢? – ormaaj