bash 中包含命令替換的變數

bash 中包含命令替換的變數

我試圖了解 bash 中的 shell 擴展(GNU bash,版本 4.4.20(1)-release (i686-pc-linux-gnu))。

在我的互動式 bash shell 中輸入

x='$(id)'
$x
$(echo $x)

我預計最後兩行中的任何一行都會出現以下形式的錯誤

bash: uid=xxx(user): command not found

但得到了

bash: $(id): command not found

我不明白為什麼這裡不發生命令替換。不是應該透過變數擴展來實現嗎?我的猜測是它與 Shell 操作有關,如這裡所述https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Operation

有人可以解釋這種行為嗎?

我只是有興趣更準確地理解 bash 擴展。我對在我的問題中運行實際腳本不感興趣。

答案1

$(…)是命令替換(「進程替換」是<(…)等等)。變數替換和命令替換發生在同一遍中,在字串中從左到右。這些替換結果中唯一發生的事情是分詞和通配符。

因此x='$(id)'設定x為 5 個字元的字串$(id)。然後,為了運行$x,shell 將替換$x為值$(id)。它不包含任何空格或通配符,因此它被視為命令名稱。

對比:

x='@(id)'
shopt -s extglob
echo /none/$x /usr/bin/$x

假設該文件/none/id不存在但/usr/bin/id確實存在,該echo命令將擴展為三個單字:(echo顯然)、/none/@(id)(glob 模式/none/@(id)不匹配任何內容,因此保持不變)和/usr/bin/id(glob 模式/usr/bin/@(id)匹配一​​個文件,因此將其替換為匹配的單元素列表)。

在bash手冊中,相關的句子位於外殼擴展部分。

展開的順序是:大括號展開;波形符擴展、參數和變數擴展、算術擴展和命令替換(以從左到右的方式完成);分詞;和檔案名稱擴充。

兩個分號之間的所有內容都是一次傳遞。每一遍都基於前一遍的結果。

請注意,單一句子(即使是像我上面引用的那樣複雜的句子)無法講述整個故事。 shell 語意很複雜。我懷疑任何 shell 的手冊都包含所有特殊情況的詳細資訊。這POSIX規範更正式,但不涵蓋 bash 特定的擴展,甚至它留下了一些未定義的非常奇怪的情況。

答案2

這是引用。單引號 ( ') 定義文字字串,且不能發生插值或轉義。雙引號 ( ") 允許插值和轉義。

這是一個例子:

$ x='$(id)'
$ echo 'The variable x contains the value \"$x\"'
The variable x contains the value \"$x\"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "$(id)"

$ x="$(id)"
$ echo "The variable x contains the value \"$x\""
The variable x contains the value "uid=1000(myusername)..."

這是基於單引號與雙引號的插值和轉義的另一個範例:

$ echo 'The current directory is $PWD according to the variable \"\$PWD\".'
The current directory is $PWD according to the variable \"\$PWD\".

$ echo "The current directory is $PWD according to the variable \"\$PWD\"."
The current directory is /tmp according to the variable "$PWD".

相關內容