Linux 中是不是有任何标准的退出状态代码?

Posted

技术标签:

【中文标题】Linux 中是不是有任何标准的退出状态代码?【英文标题】:Are there any standard exit status codes in Linux?Linux 中是否有任何标准的退出状态代码? 【发布时间】:2010-11-09 06:33:09 【问题描述】:

如果进程的退出状态为 0,则认为进程在 Linux 中已正确完成。

我已经看到分段错误通常会导致退出状态为 11,尽管我不知道这只是我工作的惯例(像这样失败的应用程序都是内部的)还是标准。

Linux 中的进程有标准退出代码吗?

【问题讨论】:

如果您正在寻找由系统函数返回的名为“系统错误号”的东西,请查看errno 【参考方案1】:

Linux 返回 0 时,表示成功。其他任何事情都意味着失败,每个程序都有自己的退出代码,所以列出它们会很长......!

关于11错误码,确实是段错误号,多半是程序访问了一个没有分配的内存位置。

【讨论】:

它总是 11,因为内核将它杀死并分配“退出值”。同样,其他类型的故障将始终获得相同的退出值。【参考方案2】:

'1' >>> 捕获一般错误

'2' >>> 滥用 shell 内置函数(根据 Bash 文档)

'126'>>> 调用的命令无法执行

'127'>>>“找不到命令”

'128'>>>退出参数无效

'128+n'>>>致命错误信号“n”

'130'>>> 脚本被 Control-C 终止

'255'>>>退出状态超出范围

这是为 bash 准备的。但是,对于其他应用程序,有不同的退出代码。

【讨论】:

看起来你们俩是在同一分钟内回答的。 Tian 必须非常快地看到您的链接并将其粘贴进去。 请注意,'control-C 产生 130' 与信号 n 的 '128+n' 一致; control-C 生成信号 2 的 SIGINT。 这似乎是从 ABS 抄袭而来,没有署名。 (我们可以判断,因为 ABS 包含不正确或至少具有误导性的信息。) 这些是保留的退出代码,根据Advanced Bash-Scripting Guide。这意味着应该避免这些值用于用户指定的退出参数【参考方案3】:

没有标准的退出代码,除了 0 表示成功。非零也不一定意味着失败。

stdlib.h 确实将 EXIT_FAILURE 定义为 1,将 EXIT_SUCCESS 定义为 0,仅此而已。

segfault 上的 11 很有趣,因为 11 是内核用来在发生段错误时终止进程的信号号。可能存在某种机制,无论是在内核中还是在 shell 中,都可以将其转换为退出代码。

【讨论】:

【参考方案4】:

程序返回一个 16 位的退出代码。如果程序被信号杀死,则高位字节包含使用的信号,否则低位字节是程序员返回的退出状态。

如何将退出代码分配给状态变量 $?然后由外壳决定。 Bash 保留状态的低 7 位,然后用 128 + (signal nr) 表示一个信号。

程序的唯一“标准”约定是 0 表示成功,非 0 表示错误。另一个约定是在出错时返回 errno。

【讨论】:

【参考方案5】:

sysexits.h 有一个标准退出代码列表。它似乎至少可以追溯到 1993 年,一些像 Postfix 这样的大项目使用它,所以我想这是要走的路。

来自 OpenBSD 手册页:

根据 style(9),使用 arbi- 调用 exit(3) 不是好习惯 结束程序时指示失败条件的值。在- 相反,应该使用来自 sysexits 的预定义退出代码,因此 进程的调用者可以粗略估计故障等级 无需查看源代码。

【讨论】:

【参考方案6】:

标准 Unix 退出代码由 sysexits.h 定义,正如另一张海报提到的那样。 Poco 等可移植库使用相同的退出代码 - 以下是它们的列表:

http://pocoproject.org/docs/Poco.Util.Application.html#16218

信号 11 是 SIGSEGV(段违规)信号,与返回码不同。该信号由内核生成,以响应错误的页面访问,从而导致程序终止。可以在信号手册页中找到信号列表(运行“man signal”)。

【讨论】:

【参考方案7】:

wait(2) & co.返回时,将8位返回码和8位杀戮信号编号混合为一个值。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>

int main() 
    int status;

    pid_t child = fork();
    if (child <= 0)
        exit(42);
    waitpid(child, &status, 0);
    if (WIFEXITED(status))
        printf("first child exited with %u\n", WEXITSTATUS(status));
    /* prints: "first child exited with 42" */

    child = fork();
    if (child <= 0)
        kill(getpid(), SIGSEGV);
    waitpid(child, &status, 0);
    if (WIFSIGNALED(status))
        printf("second child died with %u\n", WTERMSIG(status));
    /* prints: "second child died with 11" */

您如何确定退出状态?传统上,shell 只存储一个 8 位的返回码,但如果进程异常终止,则设置高位。

$ sh -c '退出 42';回声$? 42 $ sh -c '杀死-SEGV $$';回声$? 分段故障 139 $ expr 139 - 128 11

如果您看到除此之外的任何内容,则程序可能有一个 SIGSEGV 信号处理程序,然后通常会调用 exit,因此它实际上并没有被信号杀死。 (程序可以选择处理除SIGKILLSIGSTOP 之外的任何信号。)

【讨论】:

鉴于问题现在出现的方式,这似乎不是最有用(因此被接受)的答案。【参考方案8】:

第 1 部分:高级 Bash 脚本指南

一如既往,Advanced Bash Scripting Guide 有great information: (这在另一个答案中链接,但链接到非规范 URL。)

1:捕获一般错误2:滥用 shell 内置函数(根据 Bash 文档)126:调用的命令无法执行127:“找不到命令”128:退出参数无效128+n: 致命错误信号“n”255: 退出状态超出范围(退出仅接受 0 - 255 范围内的整数 args)

第 2 部分:sysexits.h

ABSG 引用 sysexits.h

在 Linux 上:

$ find /usr -name sysexits.h
/usr/include/sysexits.h
$ cat /usr/include/sysexits.h

/*
 * Copyright (c) 1987, 1993
 *  The Regents of the University of California.  All rights reserved.

 (A whole bunch of text left out.)

#define EX_OK           0       /* successful termination */
#define EX__BASE        64      /* base value for error messages */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */    
#define EX_NOUSER       67      /* addressee unknown */    
#define EX_NOHOST       68      /* host name unknown */
#define EX_UNAVAILABLE  69      /* service unavailable */
#define EX_SOFTWARE     70      /* internal software error */
#define EX_OSERR        71      /* system error (e.g., can't fork) */
#define EX_OSFILE       72      /* critical OS file missing */
#define EX_CANTCREAT    73      /* can't create (user) output file */
#define EX_IOERR        74      /* input/output error */
#define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */
#define EX_PROTOCOL     76      /* remote error in protocol */
#define EX_NOPERM       77      /* permission denied */
#define EX_CONFIG       78      /* configuration error */

#define EX__MAX 78      /* maximum listed value */

【讨论】:

请注意,在某些风格的 unix 中,某些命令使用退出状态 2 来指示其他情况。例如,许多 grep 的实现使用退出状态 2 来指示错误,并使用退出状态 1 来表示没有找到选定的行。 在 BSD 上,有一个手册页总结了来自 sysexits.h 的信息:man sysexits @NamshubWriter 所说的。 Exit status 2 是 Unix 实用程序中不正确的命令行使用的通用选择,不仅在“某些风格的 unix”中,而且在一般情况下。此答案中显示的标题不反映现在或 1987 年编写时的实际约定。 ABS 并不“好”。请阅读该主题;找到批评并不难。 但是sysexits.h的实际官方源代码在哪里? man page 大家一直引用的只是散文。例如,它引用了EX_OK,但实际上并没有像其他代码那样以规范的方式定义它。还有其他遗漏的吗?【参考方案9】:

第一个近似值,0 表示成功,非零表示失败,1 表示一般失败,大于 1 表示特定失败。除了 false 和 test 的微不足道的例外,它们都旨在为成功给出 1,我还发现了其他一些例外。

更现实地说,0 表示成功或可能失败,1 表示一般失败或可能成功,如果 1 和 0 都用于成功,则 2 表示一般失败,但也可能成功。

如果比较的文件相同,diff 命令给出 0,如果它们不同,则给出 1,如果二进制文件不同,则给出 2。 2也意味着失败。除非您未能提供参数,否则 less 命令会为失败返回 1,在这种情况下,尽管失败,它仍会退出 0。

more 命令和 spell 命令失败时给出 1,除非失败是由于权限被拒绝、文件不存在或尝试读取目录造成的。在任何这些情况下,尽管失败,它们都会退出 0。

然后 expr 命令给出 1 表示成功,除非输出为空字符串或零,在这种情况下,0 表示成功。 2和3都失败了。

在某些情况下,成功或失败是模棱两可的。当 grep 找不到模式时,它会退出 1,但如果是真正的失败(如权限被拒绝),它会退出 2。 Klist 在找不到票证时也会退出 1,尽管这实际上并不比 grep 找不到模式或 ls 空目录时更失败。

因此,不幸的是,即使在非常常用的可执行文件上,unix 的功能似乎也不会强制执行任何逻辑规则集。

【讨论】:

我也正要指出 diff 的行为。 wget 也有详细的错误(例如 6 表示身份验证失败),但随后他们使用 1 = 通用错误,2..n = 特定错误【参考方案10】:

较早的答案都没有正确描述退出状态 2。与他们声称的相反,状态 2 是您的命令行实用程序在调用不当时实际返回的内容。(是的,一个答案可能已有 9 年历史,有数百个赞成票,但仍然是错误的。)

这是正常终止的真实、长期存在的退出状态约定,即不是通过信号:

退出状态0:成功 退出状态 1:“失败”,由程序定义 退出状态2:命令行使用错误

例如,diff 如果比较的文件相同则返回 0,如果它们不同则返回 1。按照长期惯例,unix 程序在调用不正确(未知选项、错误数量的参数等)时返回退出状态 2 例如,diff -Ngrep -Ydiff a b c 将全部导致$? 被设置为 2。自 1970 年代早期的 Unix 以来,这一直是实践。

accepted answer 解释了当命令被信号终止时会发生什么。简而言之,由于未捕获的信号而终止会导致退出状态 128+[&lt;signal number&gt;。例如,SIGINT (signal 2) 终止会导致退出状态 130。

注意事项

    有几个答案将退出状态 2 定义为“滥用 bash 内置函数”。这仅适用于 bash(或 bash 脚本)以状态 2 退出时。将其视为不正确使用错误的特殊情况。

    sysexits.h,在most popular answer中提到,退出状态EX_USAGE(“命令行使用错误”)被定义为64。但这并不反映现实:我不知道任何 常见的 Unix 实用程序,在错误调用时返回 64(欢迎示例)。仔细阅读source code 会发现sysexits.h 是有抱负的,而不是真实用法的反映:

     *    This include file attempts to categorize possible error
     *    exit statuses for system programs, notably delivermail
     *    and the Berkeley network.
    
     *    Error numbers begin at EX__BASE [64] to reduce the possibility of 
     *    ***ing with oth­er exit statuses that random programs may 
     *    already return. 
    

    换句话说,这些定义并不反映当时(1993 年)的普遍做法,而是故意与之不相容。更多的是遗憾。

【讨论】:

当一个程序确实通过捕获SIGINT/Ctrl-C来处理终止时应该返回什么?还是130?除了 bash 之外,使用另一个 shell 重要吗? 与执行程序的shell无关;理论上,一个进程可以根据其父进程选择以不同状态退出,但我从未听说过发生这种情况。 如果一个程序捕获到 SIGINT、清理并退出,那么状态就是对程序有意义的任何东西。比如more会重置终端模式并退出状态为0(你可以试试)。 这个答案意味着比实际情况更高级别的标准化。值 2 的含义没有适当的标准化,因此可以预见的是实际实践非常复杂。确实,许多工具会因使用不当而返回 2,但“不当使用”的含义并没有完全明确,而且许多其他工具不遵守此约定。 如果您依赖实用程序的特定值,除非它被记录(不是在代码中,而是在手册页中),那么您不能依赖它。例如,POSIX 列出了某些实用程序的特定退出状态。回复 2 表示 X 或 64 表示 X 或任何数字表示 X 是不安全的。

以上是关于Linux 中是不是有任何标准的退出状态代码?的主要内容,如果未能解决你的问题,请参考以下文章

Android 是不是关心传递给 System.exit(...) 的退出状态代码?

转载:进程退出状态--waitpid status意义

tty详解

linux的活动进程中有个zombie是啥

来自 apache 的子进程返回退出代码 -6 而不是 stdout 或 stderr

Linux 内核进程管理 ( 进程状态 | 进程创建 | 进程终止 | 调用 exit 系统调用函数主动退出 | main 函数返回自动退出 | kill 杀死进程 | 执行异常退出 )