Bash
通過 bash 評估與管道
使用有什麼區別:
eval 'echo "foo"'
和
echo 'echo "foo"' | bash
有沒有?
簡答
執行的命令
eval
在目前 shell 中執行,通過管道傳輸的命令bash
在子 shell 中執行,例如:> echo 'x=42' | bash; echo $x > eval 'x=42'; echo $x 42
更長的答案
在評論中聲稱,在
bash
(>=4.2) 的更新版本中,第一個命令也可能具有相同的效果。然而,情況似乎並非如此。實際上有幾個因素會導致管道命令不在目前會話中執行:管道和
bash
命令。在大多數情況下,管道命令在子 shell 中執行。Bash 手冊(第 3.2.2 節:管道)有以下說法:
管道中的每個命令都在其自己的子 shell 中執行(請參閱命令執行環境)。
正如評論中所指出的,可以通過
lastpipe
選項修改此行為。Bash 手冊(第 4.3.2 節:The Shopt Builtin)對lastpipe
選項有以下說明:最後一個管道
如果設置,並且作業控制未啟動,則 shell 將在目前 shell 環境中執行未在後台執行的管道的最後一個命令。
我們可以驗證如下。
首先啟用
lastpipe
:> shopt -s lastpipe
然後禁用作業控制:
> set +m
現在執行一個從管道中設置變數的命令:
> unset x > echo x=42 | while IFS= read -r line; do eval "${line}"; done; > echo $x 42
請注意,我們使用
while
循環和read
命令作為解決方法,因為eval
命令無法從標準輸入讀取其輸入(因此無法從管道獲取其輸入)。這個例子展示了管道中最右邊的命令實際上可以在目前 shell 中執行。然而,這實際上並不影響我們原來的例子。即使
lastpipe
啟用和禁用作業控制,當管道到時我們仍然得到以下結果bash
:> echo 'x=42' | bash; echo $x >
這是因為
bash
命令本身在子 shell 中執行其輸入。