Bash

bash shell 函式中的循環名稱引用,但在 ksh 中沒有

  • January 8, 2019

我正在編寫一組我想在 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:

somethingKornShell93 完全符合我的要求,但是 Bash 失敗了,並且如果腳本中的變數被命名,也會在第 2 行警告同樣的事情var

我想讓var變數對每個函式都是本地的,這就是我使用 的原因typeset,但是 Bash 似乎不喜歡將 nameref“取消引用”到與 nameref 本身同名的變數。我不能使用local -n,或者declare -n因為它會中斷ksh缺少這些,即使我這樣做了,它也不能解決問題。

我發現的唯一解決方案是在每個函式中使用唯一的變數名,這似乎很愚蠢,因為它們是本地的。

Bash 手冊對以下內容進行了說明typeset

typeset

$$ … $$ -n 為每個名稱賦予nameref屬性,使其成為對另一個變數的名稱引用。另一個變數由 的值定義 namename除了更改 屬性本身之外,對 的所有引用和賦值 -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. varin 函式的作用域應該var全域作用域不同。這對呼叫者施加了不必要的限制。限制是“您不能隨意命名變數,因為在此函式中可能與(本地)nameref 發生名稱衝突”。

Chet Ramey(Bash 維護者)

今年早些時候在 bug-bash 上對 namerefs 進行了廣泛的討論。我對如何改變這種行為有一個合理的建議,我會在 bash-4.4 發布後研究它。

同時,我會稍微混淆我的本地 nameref 變數的名稱,這樣它們就不會在庫中發生衝突,也不會(希望)與全域 shell 變數名稱發生衝突。


bash5.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.

引用自:https://unix.stackexchange.com/questions/302578