考虑:(使用 Linux/BASH,不确定 UNIX 是否正确)
在争论一个不存在的文件时,我预计会出现 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)
Run Code Online (Sandbox Code Playgroud)
……这些都说得通,但是……
cat real-files
# Returns: 0
cat not-files
# Returns: 1 (No such file or directory)
Run Code Online (Sandbox Code Playgroud)
...“没有这样的文件或目录”不应该是退出状态为 2 的 STDERR 吗?
状态 2 随附grep
和ls
非文件,但cat
返回 1 并带有相同的错误消息。
我知道这grep
可能有三个结果(每个都在上面),但我认为ls
只有两个结果cat
。因此,两种可能的结果都不是原因,cat
因为事实并非如此ls
.
这是 BASH 代码中的问题吗?我们需要打电话给莱纳斯和理查德吗?如果这是正确的,请帮助我理解原因。
接受答案后,我希望得到一个扩展原始问题的答案,因为这是 Linux/BASH,而不是 UNIX
Ser*_*nyy 19
让我们从下到上解决一些部分,并首先摆脱不重要的部分:
这是 BASH 代码中的问题吗?
不,cat
是完全独立的二进制应用程序,与bash
. 在某些 shell 配置中,正如Stephane Chazelas所指出的,cat
可以是内置的,但即使如此,应用程序的返回状态也与该应用程序是否与 shell 相关完全分开。
我们需要打电话给莱纳斯和理查德吗?如果这是正确的,请帮助我理解原因。
不,这不是问题,Linus 和 Richard 在这里完全没有关系。好吧,更正:除非他们有一天宣布这exit()
和 errno 绝对必须相关,并且出于某种奇怪的原因,我们必须遵循他们的所有技术决定。
两个应用程序都返回不同的退出状态是完全可以的,因为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.
Run Code Online (Sandbox Code Playgroud)
对于grep,我们有:
The following exit values shall be returned:
0 One or more lines were selected.
1 No lines were selected.
>1 An error occurred.
Run Code Online (Sandbox Code Playgroud)
在 Linux 上下文中,cat(1)没有明确说明这些状态值,但GNU 文档会。grep(1)手册提到使用 2 的退出代码,但即便如此,也承认 POSIX 实现只需要大于零的错误条件,并敦促“......为了可移植性,使用测试此一般条件的逻辑而不是与 2 严格相等。”
值得一提的是,在某些情况下,假设exit()
状态值等于errno值。到目前为止,我找不到任何表明 POSIX 需要的文档或参考资料。事实上,情况恰恰相反。请注意,POSIX退出规范和 Linux exit(3) 手册页没有明确说明退出状态必须以某种方式匹配 errno。所以在 GNU 中返回值为 2 的事实grep
中与 ENOENT 错误值 2 匹配纯属巧合。
事实上,如果我们考虑errno.h 甚至不需要分配特定的整数值,而是依赖于实现。因此,很可能存在将 ENOENT 视为整数 2 的类 Unix 实现。但同样 - 这完全无关,因为退出状态和 errno 是不同的东西。
总之:
cat
返回不同的退出代码这一事实grep
是适当的并且与这些应用程序的规范一致。退出代码的含义不是固定的,取决于每个单独的应用程序(除非它是 POSIX 应用程序,如cat
或grep
,在这种情况下,为了可移植性,它们应该遵循)。
引用GNU OS 文档:“最常见的约定是 0 表示成功,1 表示失败。执行比较的程序使用不同的约定:它们使用状态 1 表示不匹配,使用状态 2 表示无法比较。您的如果现有约定对其有意义,则程序应遵循现有约定。”
Fre*_*ddy 18
在GNU的coreutils文件中cat
:
退出状态为零表示成功,非零值表示失败。
...非零退出状态表示失败,仅此而已。
的手册页grep
:
通常,如果选择了一行,退出状态为 0,如果没有选择任何行,则退出状态为 1,如果发生错误,则退出状态为 2。但是,如果使用
-q
or--quiet
或--silent
选择了一行,即使发生错误,退出状态也是 0。
和手册页ls
:
退出状态:
0 表示正常,
1 表示小问题(例如,无法访问子目录),
2 表示严重问题(例如,无法访问命令行参数)。
您的结果与文档一致。
程序的退出状态必须遵循一些规则,除了这些规则之外,还有一些通用约定。这些约定都与导致程序退出的低级错误无关。有可能编写一个程序退出时出现某个错误代码,它决定退出是因为文件不存在,如果它决定退出,因为它被拒绝访问文件的权限,以及不同的错误代码,这是可能的如果路径的目录组件结果是非目录,等等,但那将是非常不寻常且难以安排的。
程序的退出状态是一个整数值。在POSIX 系统上,该值的类型为int
,通常范围从 -2 31到 2 31 +1。然而,由于几个原因,这个范围的大部分在实践中是不可用的。首先,由于历史原因,大多数允许程序观察其子进程退出状态的接口只返回退出状态的低 8 位,即 0 到 255 之间的值。这包括系统函数wait
和waitpid
¹ 作为以及shell²中的退出状态。因此,对于几乎所有的意图和目的,退出状态都是一个 8 位值。
值 0 被视为成功,其他所有值都被视为失败。这是外壳,在外壳布尔运算符,if
并while
构造涉及真/假的概念和其他任何考虑退出状态0是真实的和任何其它身份是假的。情况也是如此make
,其中非零退出状态会导致构建停止并显示错误消息和错误状态。你可以质疑它是否是一个约定(因为程序的作者在技术上可以返回它想要的任何状态,而“成功”和“失败”无论如何都没有正式定义),但实际上,一个以状态 0 退出的程序被认为是成功的,而以另一个状态 (1-255) 退出的程序被认为是失败的。
外壳程序的另一个特别限制范围的功能是外壳程序中的退出状态(通过 观察$?
)编码其他信息:
因此,在实践中,程序不能有效地使用超过 125 的退出状态。这留下值 1-125 来表示不同的错误。
有一种普遍但远非普遍的惯例,即较大的值被视为“更糟”的失败。特别是,对于诸如 之类的搜索命令grep
,1 表示“未找到”,2 或更多表示阻止搜索的某些错误(例如,未找到文件,与找到但不包含搜索字符串的文件相反)。类似地,比较命令如cmp
和diff
以状态 0 表示“相同的文件”,1 表示“不同的文件”和 2 或更多表示“由于错误而无法完成比较”。
一些程序为不同的错误定义了不同的错误代码,例如sendmail和其他一些与邮件相关的程序(在 中定义的值sysexits.h
)、rsync、curl、wget。
到目前为止,错误代码最常见的约定是 0 表示成功,1 表示失败。C 和 C++ 编程语言定义EXIT_FAILURE
为退出状态代码,用于在没有特殊原因选择特定值时报告失败,并且EXIT_FAILURE
在大多数系统上为 1。
诸如“没有这样的文件或目录”、“权限被拒绝”、“不是目录”等错误的背后都有一个数字编码:它们是errno
值,由系统函数返回以指示出了什么问题。Errno 值通常不能用作程序的退出状态。他们对出错的细节进行编码,而不是对特定程序意味着什么。例如wget的退出状态区分“选项中的解析错误”(通常没有底层系统错误)、“本地输入/输出错误”(不管底层系统错误)、“网络故障”(这将在很大程度上与本地共享相同的系统错误I/O) 等。知道 wget 是由于网络错误还是本地文件错误而失败比知道它是否由于管道损坏(写入管道或关闭网络套接字上的连接?)或权限错误(无法读取配置文件,或本地策略拒绝网络访问?)。
返回状态遵循 errno 值的情况有些罕见。由于 Perldie
函数的工作方式,它确实会发生,尤其是对于 Perl 脚本。但这是一个坏主意,不仅因为正如我上面提到的,errno 值很少是信息中最有用的部分,而且主要是因为 errno 值没有理由在 1-125 的范围内。幸运的是,我不知道任何 errno 值在 1-255 范围之外的系统,因此至少exit(errno)
(或 Perl 的die
)不会以 256 的倍数退出,正如我们在上面看到的那样,这表示成功。但是在 Linux 上,例如,它们确实达到了 126,并且一个程序以exit(errno)
以errno == ERFKILL
(“由于 RF-kill 导致无法操作”)将无法与 shell 与因 SIGILL(非法指令)而死亡的程序区分开来。
¹授予通过.
²通过或其他方式。例如,如果是一个以 退出的程序,shell 命令会打印“以 0 退出”。 waitid
int
infop->si_status
$?
exit256
exit(256)
if exit256; then echo "exited with 0"; fi
归档时间: |
|
查看次数: |
3369 次 |
最近记录: |