![Shell 脚本退出代码](https://linux22.com/image/209631/Shell%20%E8%84%9A%E6%9C%AC%E9%80%80%E5%87%BA%E4%BB%A3%E7%A0%81.png)
我有一个关于 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 服务器将根据本地传递代理返回的精确退出状态字执行不同的操作。硬退回与服务器可能会再次尝试的临时传送失败有很大不同。