bash shell 函式中的循環名稱引用,但在 ksh 中沒有
我正在編寫一組我想在 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"
執行它:
$ ksh script.sh hello:boff $ bash script.sh script.sh: line 4: warning: var: circular name reference hello:
something
KornShell93 完全符合我的要求,但是 Bash 失敗了,並且如果腳本中的變數被命名,也會在第 2 行警告同樣的事情var
。我想讓
var
變數對每個函式都是本地的,這就是我使用 的原因typeset
,但是 Bash 似乎不喜歡將 nameref“取消引用”到與 nameref 本身同名的變數。我不能使用local -n
,或者declare -n
因為它會中斷ksh
缺少這些,即使我這樣做了,它也不能解決問題。我發現的唯一解決方案是在每個函式中使用唯一的變數名,這似乎很愚蠢,因為它們是本地的。
Bash 手冊對以下內容進行了說明
typeset
:
typeset
$$ … $$
-n
為每個名稱賦予nameref
屬性,使其成為對另一個變數的名稱引用。另一個變數由 的值定義name
。name
除了更改 屬性本身之外,對 的所有引用和賦值-n
都是在 name 值引用的變數上執行的。$$ … $$ 在函式中使用時,
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
結果在
bash: warning: var: circular name reference
.var
in 函式的作用域應該與var
全域作用域不同。這對呼叫者施加了不必要的限制。限制是“您不能隨意命名變數,因為在此函式中可能與(本地)nameref 發生名稱衝突”。
Chet Ramey(Bash 維護者)說
今年早些時候在 bug-bash 上對 namerefs 進行了廣泛的討論。我對如何改變這種行為有一個合理的建議,我會在 bash-4.4 發布後研究它。
同時,我會稍微混淆我的本地 nameref 變數的名稱,這樣它們就不會在庫中發生衝突,也不會(希望)與全域 shell 變數名稱發生衝突。
在
bash
5.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
這表明它有效,但也有一些警告。
相關的新聞條目說
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.