2013-04-01 44 views
1

首先,我知道使用function關鍵字functionmyfunction()聲明函數時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 

觀察:

  • readonlytypeset -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而不值
    • 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只在功能範圍內變爲只讀。
    • readonly好像在[6]和[9]中聲明瞭新的局部變量,但在[8]中沒有聲明新的局部變量。

bash的行爲是預期的。 typeset(= declare)的功能範圍創建/修改(bash把-g選項強制在函數內部使用,即使在全球範圍內創建/修改),readonly真的只有「標記」現有的變量,從來沒有引入新的局部變量。 [5]困擾了我一點點,因爲我以前從未做過的聲明未設置只讀變量,我會假設,如果相同名字的全局變量存在,它修改了,但我可以接受這種行爲絕對生活,因爲它是一致的與其他場景和-g的存在。

但就我的理解,ksh手冊頁未能完全解釋上述所有情況以及readonlytypeset -r關鍵字之間的細微差異,除非我在重新閱讀問題中的相應部分時錯過了某些內容。 我最困惑的是沒有提到關鍵字readonly附近的解釋foo()function bar之間的範圍區別的解釋,readonly內置的簡短說明也沒有提到這一點。基於此,我永遠不會假設readonly引入了像typeset -r這樣的靜態範圍的新變量,它在一些(但不是所有)場景中都會這樣做。

對我來說最令人困惑的情景是[6],我不明白到底發生了什麼(這也是破壞我的代碼的特定場景)。

我的觀察是否正確,並且有人可以闡明ksh93的行爲? (我希望這個問題是可以接受的範圍的(沒有雙關語意))

+0

稍後我會有時間仔細閱讀。與此同時,你有沒有閱讀[此線程](http://gnu-bash.2382.n7.nabble.com/inconsistency-with-quot-readonly-quot-and-scope-td5400.html#none)呢? – ormaaj

回答

1

歡迎外殼不兼容:)

的世界,如果我理解正確的問題,它是關於

功能等等的區別{}

嗒嗒(){}

看廣告的人的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

你完全錯過了我的問題的重點,並且你讀了我的第一句話,你就會知道我知道'function foo'和'foo()'之間的一般區別,關鍵在於只讀變量以及它們如何聲明或設置爲只讀;-) –

+0

嗨,是的,很抱歉,我完全誤讀了您的文本。我正在尋找容易的問題,以獲得聲譽的錯誤足以能夠評論不同的主題... – Neuron

1

的錯誤是如下,對於功能時,沒有 「本地」 範圍你不使用"local"或使功能成爲一個子殼!

因此,使用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