Bash

在沒有子shell的if語句中比較命令輸出

  • February 19, 2019

根據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 ]...

但是,雖然這避免了 subshel​​l,但這意味著在文件系統中亂扔file.

type是一個內置的。它的輸出是由 shell 生成的,確實感覺有點傻,必須派生一個程序才能在 shell 中使用該輸出。

一些 shell (ksh93fish) 確實在那裡實現了一些優化。在他們的$(type echo)( (type echo)in fish) 中,他們實際上偽造了輸出的寫入和讀取(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 中,可以以這樣的方式呼叫許多內置函式,而不是寫入結果,而是將其儲存在變數中。

最明顯的是標準readgetopts預設情況下會這樣做(你這樣做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

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