Cat

為什麼失敗的貓返回 1,而其他失敗的貓返回 2?

  • June 3, 2020

考慮:(使用 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 帶有grepls非文件,但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與這些應用程序的適當且符合規範不同的事實。退出程式碼的含義不是固定的,並且取決於每個單獨的應用程序(除非它是類似cator的 POSIX 應用程序grep,在這種情況下,為了可移植性,它們應該遵循)。

引用GNU OS 文件:“最常見的約定只是 0 表示成功,1 表示失敗。執行比較的程序使用不同的約定:它們使用狀態 1 表示不匹配,使用狀態 2 表示無法比較。您的如果現有約定對程序有意義,則程序應遵循現有約定。”

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