Shell 脚本退出代码

Shell 脚本退出代码

我有一个关于 bash 退出代码的问题。我可以基本上定义我返回的每个代码的含义吗?如果是这样,是否有某种标准方法来定义或记录它?

我一直在研究它,发现有各种“常见”退出代码列表。例如

我还查看了一些 GNU 文档,发现它有点令人困惑。

退出状态介于 0 和 255 之间,但如下所述,shell 可能会特别使用高于 125 的值。

我只是好奇是否有任何类型的标准做法。

答案1

上面的代码大部分都是废话。这不是正式的定义。我发现了另一个高级 Bash 脚本指南

Exit Code Number
1   Catchall for general errors
2   Misuse of shell builtins (according to Bash documentation)
126 Command invoked cannot execute
127 "command not found"
128 Invalid argument to exit
128+n   Fatal error signal "n"
130 Script terminated by Control-C
255*    Exit status out of range

但这些代码是建议因此,请随意将它们用于您的目的。

答案2

status是一个 16 位字(类似于 JSON,但在 20 世纪 70 年代,16 位寄存器是一种稀有商品,尤其是在像 之类的复杂事物之后fork),其中各个位或位范围具有特定含义。 Perl 将调用设置的 16 位字wait(2)放入变量中$?,我们可以通过移动高位来找到特定的退出代码,因为那是该字段在字中的位置:

$ perl -e 'fork || exit 42; wait; printf "%016b\n", $?'
0010101000000000
$ perl -e 'fork || exit 42; wait; printf "%016b\n", $? >> 8'
0000000000101010
$ perl -e 'fork || exit 42; wait; printf "%d\n", $? >> 8'
42

Unix shell 将 16 位status字转换成不同的形式:

$ perl -e 'exit 42'; echo $?
42

如果存在核心转储(16 位字中有一个标志)或信号,这就会变得相关:

$ perl -MPOSIX -e 'raise SIGTERM'; echo $?
Terminated
143
$ echo $((143-128))
15
$ kill -l | grep 15
15   TERM Terminated                    31   USR2 User defined signal 2

因此,这是信号号加上 128(shell 修改该值),在实际的 16 位退出状态字中,它显示为:

$ perl -MPOSIX -e 'fork || raise SIGTERM; wait; printf "%016b\n", $?'
0000000000001111
$ perl -E 'say 0b1111'
15

因此,Perl 直接使用调用返回的 16 位字wait(2),而 Unix shell 将其转换成其他形式。根据您使用的语言,您需要遵循 C 约定并执行诸如“左移以获取退出代码”之类的操作(通常有宏或其他此类调用来协助完成此操作,请查看详细文档详细信息),或者如果使用 shell 损坏值,则“减去 128 以找到信号编号”。

为了获得额外的分数,创建一个程序来创建一个核心文件并查看退出状态字是什么样的,或者尝试不同的信号号等。

如何使用状态字

有多种约定可能会或可能不会被反对,例如来自的退出代码sysexits.h;其中一些代码对于电子邮件传送系统(历史上的方式sendmail)很重要,其中特定代码可用于表示“重试”临时失败(在 SMTP 中成为 4xx 代码),而不是“拒绝并重试”。退回该电子邮件”(5xx),您可能会在邮件传递代理软件(例如procmail或类似软件)中看到对此的引用。

$ grep EX_TEMPFAIL /usr/include/sysexits.h
 *      EX_TEMPFAIL -- temporary failure, indicating something that
#define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */

否则,0通常意味着“好的”(但是如果不设置非零代码,程序可能会失败,买家要小心!),而任何“不”的0意思是“不好”(但这到底意味着什么不同,它可能是暂时的故障,噪音忽略,事情真的很糟糕,等等)。特定退出代码可能具有特定于站点、供应商或软件的含义;这些特定代码可能会或可能不会被记录。页面man通常可能有一个通用.Ex -std宏来生成类似的简介

EXIT STATUS
     The foo utility exits 0 on success, and >0 if an error occurs.

或者根据需要提供更具体的文档(如果软件有详细文档记录)。很多软件没有很好的文档记录......

这什么时候很重要

监控或测试服可能确实需要区分“任何旧的非零退出”和程序突然退出并出现段错误或核心转储,或者段错误可能是特定测试的预期值,并且如果不发生这种情况是不寻常的。仅报告 0 或不报告 0 的监视或测试将忽略有价值的调试信息。

如上所述,SMTP 服务器将根据本地传递代理返回的精确退出状态字执行不同的操作。硬退回与服务器可能会再次尝试的临时传送失败有很大不同。

相关内容