在沒有子shell的if語句中比較命令輸出
根據https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
在大括號之間放置一個命令列表會導致該列表在目前 shell 上下文中執行。
但是當我嘗試這個時:
if [[ { type -t echo; } = "builtin" ]]; then echo 1; else echo 0; fi
我收到以下錯誤:-bash:需要條件二元運算符
-bash:“類型”附近的語法錯誤
沒關係,我知道它不應該那樣使用。現在我知道,如果我使用
if [[ $( type -t echo ) = "builtin" ]]; then echo 1; else echo 0; fi
,理論上我將實現所需的功能。我發現其他關於防止不必要地使用子shell的問題得到了解答,但沒有一個解釋了比較沒有子shell的命令的輸出。我真正想要的是避免在不需要的地方使用子shell,如果可能的話,我真的很想在目前的shell上下文中執行這個檢查——感覺這就是它應該完成的方式。PS如果沒有其他方法,我不介意使用變數和操作。
要獲得命令的輸出,您需要以某種方式閱讀它。
type
將其寫入其標準輸出。我們需要以某種方式獲取它並將其傳遞給[
命令。
$(...)
為此使用管道。但是對於管道,您需要一個編寫器和一個讀取器程序,因此即使執行內置命令也必須派生一個程序。您可以嘗試在同一程序中讀取和寫入管道,但這通常容易出現死鎖,因為如果沒有人在讀取,寫入可能會阻塞(儘管您需要管道緩衝區填滿才能發生這種情況,這不太可能發生type
)。您可以使用
yash
具有以下原始介面的外殼來執行此操作pipe()
:{ type echo >&3 echo 3>&- # close the writing end so the reader can see an eof IFS= read -r answer <&4 } 3>>|4
上面,如果
type
’ 的輸出大於管道緩衝區大小(現代版本的 Linux 上預設為 64KiB),您將遇到死鎖。使用
bash
,您總是可以這樣做:type -t echo > file IFS= read -rd '' type < file if [ "$type" = builtin ]...
但是,雖然這避免了 subshell,但這意味著在文件系統中亂扔
file
.這
type
是一個內置的。它的輸出是由 shell 生成的,確實感覺有點傻,必須派生一個程序才能在 shell 中使用該輸出。一些 shell (
ksh93
和fish
) 確實在那裡實現了一些優化。在他們的$(type echo)
((type echo)
infish
) 中,他們實際上偽造了輸出的寫入和讀取(FreeBSDsh
也為單個內置呼叫(如type
這裡)這樣做)。當內置的標準輸出是命令替換時,shell 只是將可能輸出的文本附加到命令替換結果中,而不是寫入輸出,並且不需要 fork。實際上,
fish
’s(type echo)
更像ksh93
’s${ type echo;}
,因為它甚至不創建子外殼環境。With$(...)
,ksh93
模擬一個子shell環境,使它看起來好像一個子程序被分叉來解釋其中的程式碼,並且不會對其${ ...;}
變體執行此操作。ksh93$ a=1 ksh93$ echo "$(a=2; type echo) $a" echo is a shell builtin 1 ksh93$ echo "${ a=3; type echo;} $a" echo is a shell builtin 3
fish> set a 1 fish> echo (set a 2; type echo) $a echo is a builtin 2
您會發現在一些不進行優化的 shell 中,可以以這樣的方式呼叫許多內置函式,而不是寫入結果,而是將其儲存在變數中。
最明顯的是標準
read
,getopts
預設情況下會這樣做(你這樣做IFS= read -r var
而不是var=$(line)
)。bash
並且zsh
還有printf -v variable format args
.zsh
可以對其stat
,strftime
… 內置函式執行相同的操作。一些 shell 還會在一些特殊變數中自動提供一些資訊,比如*’*
ksh
s$SECONDS
和$RANDOM
在其他一些 shell(以及標準的 shell 中,如$-
,$#
(例如相當於fish
’s(count $argv)
))。在
zsh
中,這已推廣到大多數 shell 的內部資訊,因此您幾乎不需要在內置命令的輸出上使用命令替換。例如,它有內置函式、關鍵字、命令列表的關聯數組……if (($+builtins[echo])); then echo echo is a builtin fi