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


308

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

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

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


6
如果您正在寻找系统功能返回的“系统错误号”,请看errno
marinara 2012年

Answers:


86

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'kill -SEGV $$'; 回声$?
分段故障
139
$ expr 139-128
11

如果您看到的不是此内容,则程序可能有一个SIGSEGV信号处理程序,该信号处理程序随后exit会正常调用,因此实际上并没有被信号杀死。(程序可以选择处理SIGKILL和以外的任何信号SIGSTOP。)


8
考虑到问题出现的方式,这似乎不是最有用(因此也被接受)的答案。
David J.

332

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

与往常一样,《高级Bash脚本指南》提供了很多信息:(这是在另一个答案中链接的,但链接到非规范的URL。)

1: 针对一般错误的Catchall
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 */

5
请注意,在某些类型的Unix中,某些命令使用退出状态2表示其他情况。例如,许多grep实现使用退出状态2表示错误,使用退出状态1表示未找到选定的行。
NamshubWriter 2012年

3
在BSD上,有一个手册页,汇总了sysexits.h中的信息:man sysexits
georgebrock

6
@NamshubWriter说了什么。退出状态2是Unix实用程序中不正确使用命令行的通用方法,不仅是“某些类型的unix”,而且通常也是这样。此答案中显示的标头现在或当它在1987
。– Alexis,2017年

ABS不是“伟大的”。请仔细阅读该主题;很难找到批评。
人间

但是实际的官方源代码在sysexits.h哪里?大家一直引用的手册页只是散文。例如,它引用EX_OK但实际上并未像其他代码一样以规范的方式定义它。还有更多缺少的东西吗?
Garret Wilson

71

'1' >>> Catchall,用于一般错误

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

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

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

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

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

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

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

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


1
看起来你们俩都在同一分钟内回答了。田必须是相当快的,看看你的链接,并将其贴上它。
内森·费尔曼

6
注意,“控制C的输出130”与信号n的“ 128 + n”一致;控制-C生成SIGINT这是信号2
乔纳森莱弗勒

3
这似乎是从ABS抄袭而来的,但没有注明出处。(我们可以知道,因为ABS包含不正确或至少具有误导性的信息。)
点钟

4
根据高级Bash脚本指南,这些是保留的退出代码。因此,对于用户指定的退出参数,应避免使用这些值。
ingyhere

53

较早的答案均未正确描述退出状态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年)的通用做法,但有意与此不符。更可惜。


应该怎样当一个程序返回通过捕捉SIGINT /按Ctrl-C处理终止?还是130?除了bash之外,其他外壳的使用是否重要?
Gringo Suave

1
执行程序的外壳无关紧要;理论上,一个进程可以根据其父进程选择以不同的状态退出,但我从未听说过这种情况。
Alexis

1
如果某个程序捕获了SIGINT,清理并退出,则该状态对于该程序有意义。例如,more将重置终端模式并以状态0退出(您可以尝试)。
Alexis

1
这个答案暗示了比实际情况高得多的标准化等级。值2的含义没有适当的标准化,因此可以预见的是,实际做法是非常复杂的。的确,许多工具针对不正确的使用会返回2,但是“不正确的使用”的含义还不是很明确,还有许多其他工具不遵守该约定。
tripleee

@tripleee“工具”也没有很好的定义!:-)当然,任何人都可以编写命令行程序,并且它可以返回任何内容,但是老式的“ Unix命令行实用程序”比Linux或GNU coreutils的内容要长得多。对此保持一致。否则,请命名该组中不使用状态2的某些工具。另外,“不当使用”是您的用语(我同意这是一个模糊的用语);我写的“命令行用法错误”,这是非常具体的:不存在或不兼容的选项,错号的非选项参数,等等
亚历克西斯

25

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

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

segfault上的11很有趣,因为11是发生segfault时内核用于终止进程的信号编号。内核或外壳中可能存在某种机制,可以将其转换为退出代码。


20

sysexits.h包含标准退出代码的列表。它似乎至少可以追溯到1993年,并且一些大型项目(如Postfix)都在使用它,所以我想这是要走的路。

在OpenBSD手册页中:

根据style(9),在结束程序时,用任意值调用exit(3)来指示失败状态是一种不好的做法。相反,应该使用sysexits的预定义退出代码,这样,过程调用者可以在不查找源代码的情况下大致了解故障类别。

8

近似地,成功是0,非失败是失败,其中1是一般性失败,大于1的是特定失败。除了琐碎的false和test异常(都被设计为给成功1)之外,还有其他一些异常。

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

如果比较的文件相同,则diff命令给出0;如果它们不同,则给出1;如果二进制文件不同,则给出2。2也表示失败。less命令为失败提供1,除非您未能提供参数,在这种情况下,即使失败,它也会退出0。

除非失败是由于权限被拒绝,文件不存在或尝试读取目录而导致的,否则more命令和spell命令会为失败给出1。在任何这些情况下,尽管失败,它们仍将退出0。

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

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

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


我也要指出diff的行为。wget也有详细的错误(例如,6个身份验证失败),但是它们使用1 =通用错误,2..n =特定错误
PypeBros

5

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

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

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


3

标准的Unix退出代码由sysexits.h定义,如前所述。便携式库(例如Poco)使用相同的退出代码-以下是它们的列表:

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

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


1

当Linux返回0时,表示成功。其他任何方法都意味着失败,每个程序都有其自己的退出代码,因此将它们全部列出会很长。

关于11个错误代码,它的确是分段错误号,主要是指程序访问了未分配的内存位置。


1
它始终为11,因为内核会杀死它并分配“退出值”。同样,其他类型的故障将始终获得相同的退出值。
Alex Gartrell,2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.