Exit-Status

基於命令的 if 語句

  • October 27, 2017

我發現這種方式來執行if命令:

$if echo test | grep st ; then echo yes ; fi ; echo $?
test
yes
0

看起來挺好的。讓我們嘗試一個不匹配:

$if echo test | grep 123 ; then echo yes ; fi ; echo $?
0

那是不對的。該if語句正常執行,但返回零退出程式碼。

有人可以為我解釋一下嗎?

$?塊之後if包含if語句的退出狀態。該標準規定

命令的退出狀態if應為已執行的thenelse 複合列表的退出狀態,如果未執行,則為零。

在第一種情況下,您會看到echo yes命令的退出狀態。then第二種情況,在or塊中沒有執行任何命令else,所以退出狀態為 0。

來自 bash 手冊(添加了格式和重點):

如果列表;然後列出;$$ elif list; then list; $$…$$ else list; $$是

if 列表被執行。如果其退出狀態為零,則執行 then 列表。否則,依次執行每個 elif 列表,如果其退出狀態為零,則執行相應的 then 列表並完成命令。否則,執行 else 列表(如果存在)。退出狀態是最後執行的命令的退出狀態,如果沒有條件測試為真,則為零。

因此,重要的部分是了解您實際查看的內容的退出狀態。在您的範例中,echo test | grep 123最後一個命令沒有成功退出。如果你先做了grep然後測試了退出狀態,你會看到它返回非零退出狀態:

$ grep 'noexist' /etc/passwd
$ echo $?
1

相比之下,在 if 語句中,作為條件的命令沒有測試為真,因此根據規範和手冊 - 退出狀態為 0。

請注意,grep '123'如果您目前目錄中有文件 123,則未引用的模式可能是其他問題。


關於 grep 和引用模式的旁注

Stephen Kitt 在評論中要求對最後一段進行詳細說明。這不一定與這個問題的主題相關,這裡已經提到過,我在這裡回答了類似的問題,但我會切線,因為這很有趣。讓我們看兩個例子。

在這裡,我們有一個grep input簡單的不帶引號的字元串。grep的語法是這樣的,它會將第一個字元串視為模式。這裡沒問題,這有效:

bash-4.3$ strace -e trace=execve grep input <<< "this is input line"
execve("/bin/grep", ["grep", "input"], [/* 80 vars */]) = 0
this is input line
+++ exited with 0 +++

但是,看看當你有(你認為是)正則表達式時會發生什麼。

bash-4.3$ strace -e trace=execve grep input* <<< "this is input line"
execve("/bin/grep", ["grep", "input.txt", "input.txt.bak"], [/* 80 vars */]) = 0
+++ exited with 1 +++

shell 看到了你*並執行了路徑名擴展。現在 shell 執行的實際命令是grep some_file_1 some_file_2 some_file_3,並且按照grep語法grep [OPTIONS] PATTERN [FILE...]- 該命令現在將input.txt在裡面查找字元串input.txt.bak。其實看看這個:

bash-4.3$ echo "I have input.txt here" > input.txt.bak
bash-4.3$ grep input* <<< "this is input line"
I have input.txt here

輸入字元串被完全忽略,grep只搜尋擴展的文件名,你得到了你不想要的結果。

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