346

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

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

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

4

10 回答 10

364

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

与往常一样,Advanced Bash Scripting Guide提供了大量信息:(这在另一个答案中链接,但链接到非规范 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 */
于 2009-10-08T05:08:06.183 回答
92

wait(2)返回代码的 8 位和杀戮信号的 8 位编号在 from & co返回时混合为单个值。.

#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,所以它实际上并没有被信号杀死。(程序可以选择处理除SIGKILL和之外的任何信号SIGSTOP。)

于 2009-07-09T15:28:55.840 回答
75

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

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

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

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

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

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

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

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

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

于 2009-07-09T05:28:43.063 回答
71

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

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

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

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

接受的答案解释了当命令被信号终止时会发生什么。简而言之,由于未捕获信号而终止会导致退出状态128+[<signal number>SIGINT例如,由(信号 2 )终止导致退出状态 130。

笔记

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

  2. 最流行的答案sysexits.h中提到,退出状态(“命令行使用错误”)被定义为 64。但这并不反映现实:我不知道有任何常见的 Unix 实用程序在错误调用时返回 64(欢迎示例)。仔细阅读源代码会发现这是有抱负的,而不是真实用法的反映:EX_USAGEsysexits.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 
     *    clashing with oth­er exit statuses that random programs may 
     *    already return. 
    

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

于 2016-11-08T10:33:45.093 回答
24

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

stdlib.h 确实定义EXIT_FAILURE为 1 和EXIT_SUCCESS0,但仅此而已。

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

于 2009-07-09T05:29:47.243 回答
21

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

从 OpenBSD 手册页:

根据 style(9),在结束程序时使用任意值调用 exit(3) 来指示失败情况并不是一个好习惯。相反,应该使用来自 sysexits 的预定义退出代码,因此进程的调用者可以在不查找源代码的情况下获得关于故障类的粗略估计。
于 2009-07-09T05:56:47.517 回答
10

对于第一个近似值,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 的权力似乎也没有强制执行任何逻辑规则集。

于 2015-06-10T05:20:49.020 回答
5

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

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

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

于 2009-07-09T05:43:13.300 回答
4

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

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

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

于 2009-07-09T06:54:02.347 回答
1

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

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

于 2009-07-09T05:28:05.420 回答