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

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

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


当前回答

返回码的8位和终止信号的8位数字被混合成从wait(2) & 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 'exit 42'; echo $?
42
$ sh -c 'kill -SEGV $$'; echo $?
Segmentation fault
139
$ expr 139 - 128
11

如果你看到的不是这个,那么程序可能有一个SIGSEGV信号处理程序,然后正常调用exit,所以它实际上没有被信号杀死。(程序可以选择处理除SIGKILL和SIGSTOP之外的任何信号。)

其他回答

返回码的8位和终止信号的8位数字被混合成从wait(2) & 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 'exit 42'; echo $?
42
$ sh -c 'kill -SEGV $$'; echo $?
Segmentation fault
139
$ expr 139 - 128
11

如果你看到的不是这个,那么程序可能有一个SIGSEGV信号处理程序,然后正常调用exit,所以它实际上没有被信号杀死。(程序可以选择处理除SIGKILL和SIGSTOP之外的任何信号。)

以前的答案都没有正确描述退出状态2。与他们声称的相反,状态2是您的命令行实用程序在不正确调用时实际返回的结果。(是的,一个答案可能是九年前的事了,得到了数百个赞,但仍然是错误的。)

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

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

例如,如果比较的文件相同,diff返回0,如果不同则返回1。根据长期以来的惯例,unix程序在被错误调用(未知选项,错误的参数数量等)时返回退出状态2。例如,diff -N, grep -Y或diff a b c都将导致$?被设置为2。这是自20世纪70年代Unix早期以来的实践。

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

笔记

Several answers define exit status 2 as "Misuse of bash builtins". This applies only when bash (or a bash script) exits with status 2. Consider it a special case of incorrect usage error. In sysexits.h, mentioned in the most popular answer, exit status EX_USAGE ("command line usage error") is defined to be 64. But this does not reflect reality: I am not aware of any common Unix utility that returns 64 on incorrect invocation (examples welcome). Careful reading of the source code reveals that sysexits.h is aspirational, rather than a reflection of true usage: * 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. In other words, these definitions do not reflect the common practice at the time (1993) but were intentionally incompatible with it. More's the pity.

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

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

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

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

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

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

正如David提到的,标准的Unix退出码是由sysexits.h定义的。 类似Poco这样的可移植库也使用相同的退出码——下面是它们的列表:

类Poco::Util::Application, ExitCode

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