為什麼失敗的貓返回 1,而其他失敗的貓返回 2?
考慮:(使用 Linux/BASH,不確定 UNIX Proper)
當爭論一個不存在的文件時,我期待一個 2 錯誤……
grep "i am here" real-file # Returns: 0 (via: echo $?) grep "i am not here" real-file # Returns: 1 grep "i am not here" not-a-file # Returns: 2 (No such file or directory) ls real-files # Returns: 0 ls not-files # Returns: 2 (No such file or directory)
……這些是有道理的,但是……
cat real-files # Returns: 0 cat not-files # Returns: 1 (No such file or directory)
…“沒有這樣的文件或目錄”不應該是退出狀態為 2 的 STDERR 嗎?
狀態 2 帶有
grep
和ls
非文件,但cat
返回 1 和相同的錯誤消息。我認識到這
grep
可能有三個結果(每個結果都在上面),但我認為ls
只會有兩個結果cat
。所以,兩個可能的結果不可能是原因,cat
因為它不是這樣ls
。這是 BASH 程式碼中的問題嗎?我們需要打電話給 Linus 和 Richard 嗎?如果這是正確的,請幫助我理解原因。
接受答案後,我希望得到一個擴展原始問題的答案,因為這是 Linux/BASH,而不是 UNIX Proper:UNIX(即在 Mac 上)是否做同樣的事情或類似的事情?
讓我們從下到上處理一些部分,並首先擺脫不重要的部分:
這是 BASH 程式碼中的問題嗎?
不,
cat
是完全獨立的二進制應用程序,與bash
. 正如Stephane Chazelas所指出的,在某些 shell 配置中,cat
可以是內置的,但即便如此,應用程序的返回狀態也完全與該應用程序是否與 shell 相關。我們需要打電話給 Linus 和 Richard 嗎?如果這是正確的,請幫助我理解原因。
不,這不是問題,Linus 和 Richard 在這裡完全沒有關係。好吧,更正:除非他們有一天宣布
exit()
和 errno 絕對必須相關,並且出於某種奇怪的原因,我們必須遵循他們所有的技術決定。兩個應用程序返回不同的退出狀態是完全可以的,因為POSIX 規範沒有明確的限製或分配說“這個非零退出狀態應該意味著這個和那個”。
退出系統呼叫狀態的 POSIX 文件:
status 的值可以是 0、EXIT_SUCCESS、EXIT_FAILURE 或任何其他值,儘管只有最低有效 8 位(即 status & 0377)可供等待的父程序使用。
這意味著只有狀態 0 具有指定的含義,它按照stdlib.h規範中的指定分配給 EXIT_SUCCESS。但這是 POSIX 規範,Linux 規範如何比較?嗯,大致相同:Linux exit(3)手冊甚至沒有指定可能的值是什麼。
另請注意,它說“可能”而不是“應該”,因為即使在出現錯誤的情況下,**應用程序也不是絕對需要以特定值退出。**您的應用程序可能會遇到錯誤或失敗,並且在退出時仍返回 0。
但是,每個可移植應用程序的POSIX 規範確實指定了 EXIT STATUS 部分,該部分**特定於每個應用程序。**同樣,除了 0 表示成功和非零表示其他任何模式之外,沒有其他模式。例如,POSIX cat 規範要求:
The following exit values shall be returned: 0 All input files were output successfully. >0 An error occurred.
對於grep我們有:
The following exit values shall be returned: 0 One or more lines were selected. 1 No lines were selected. >1 An error occurred.
在 Linux 上下文中,cat(1)沒有明確說明這些狀態值,但GNU 文件會。grep(1)手冊提到使用退出程式碼 2,但即便如此,也承認 POSIX 實現只需要大於零的錯誤條件並敦促“……為了可移植性,使用測試這種一般條件的邏輯而不是與 2 嚴格相等。”
值得一提的是,在某些情況下,假設
exit()
狀態值等於errno值。到目前為止,我找不到任何表明 POSIX 需要的文件或參考資料。事實上,情況恰恰相反。請注意,POSIX退出規範和 Linux exit(3) 手冊頁沒有明確聲明退出狀態必須以某種方式匹配 errno。grep
因此,GNU 中的返回值 2與 ENOENT 錯誤值 2 匹配的事實純屬巧合。事實上,如果我們考慮errno.h 甚至不需要分配特定的整數值,並且取決於實現。因此,很可能存在將 ENOENT 視為整數 2 的類 Unix 實現。但同樣 - 這完全不相關,因為退出狀態和 errno 是不同的東西。
總之:
cat
返回的退出程式碼grep
與這些應用程序的適當且符合規範不同的事實。退出程式碼的含義不是固定的,並且取決於每個單獨的應用程序(除非它是類似cat
or的 POSIX 應用程序grep
,在這種情況下,為了可移植性,它們應該遵循)。引用GNU OS 文件:“最常見的約定只是 0 表示成功,1 表示失敗。執行比較的程序使用不同的約定:它們使用狀態 1 表示不匹配,使用狀態 2 表示無法比較。您的如果現有約定對程序有意義,則程序應遵循現有約定。”