Are there any standard exit status codes in Linux?

2018-12-31 10:18发布

A process is considered to have completed correctly in Linux if its exit status was 0.

I've seen that segmentation faults often result in an exit status of 11, though I don't know if this is simply the convention where I work (the apps that failed like that have all been internal) or a standard.

Are there standard exit codes for processes in Linux?

10条回答
君临天下
2楼-- · 2018-12-31 10:45

To a first approximation, 0 is sucess, non-zero is failure, with 1 being general failure, and anything larger than one being a specific failure. Aside from the trivial exceptions of false and test, which are both designed to give 1 for sucess, there's a few other exceptions I found.

More realistically, 0 means sucess or maybe failure, 1 means general failure or maybe sucess, 2 means general failure if 1 and 0 are both used for sucess, but maybe sucess as well.

The diff command gives 0 if files compared are identical, 1 if they differ, and 2 if binaries are different. 2 also means failure. The less command gives 1 for failure unless you fail to supply an argument, in which case, it exits 0 despite failing.

The more command and the spell command give 1 for failure, unless the failure is a result of permission denied, nonexistent file, or attempt to read a directory. In any of these cases, they exit 0 despite failing.

Then the expr command gives 1 for sucess unless the output is the empty string or zero, in which case, 0 is sucess. 2 and 3 are failure.

Then there's cases where success or failure is ambiguous. When grep fails to find a pattern, it exits 1, but it exits 2 for a genuine failure (like permission denied). Klist also exits 1 when it fails to find a ticket, although this isn't really any more of a failure than when grep doesn't find a pattern, or when you ls an empty directory.

So, unfortunately, the unix powers that be don't seem to enforce any logical set of rules, even on very commonly used executables.

查看更多
看风景的人
3楼-- · 2018-12-31 10:46

Standard Unix exit codes are defined by sysexits.h, as another poster mentioned. The same exit codes are used by portable libraries such as Poco - here is a list of them:

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

A signal 11 is a SIGSEGV (segment violation) signal, which is different from a return code. This signal is generated by the kernel in response to a bad page access, which causes the program to terminate. A list of signals can be found in the signal man page (run "man signal").

查看更多
孤独寂梦人
4楼-- · 2018-12-31 10:48

None of the older answers describe exit status 2 correctly. Contrary to what they claim, status 2 is what your command line utilities actually return when called improperly. (Yes, an answer can be nine years old, have hundreds of upvotes, and still be wrong.)

Here is the real, long-standing exit status convention for normal termination, i.e. not by signal:

  • Exit status 0: success
  • Exit status 1: "failure", as defined by the program
  • Exit status 2: command line usage error

For example, diff returns 0 if the files it compares are identical, and 1 if they differ. By long-standing convention, unix programs return exit status 2 when called incorrectly (unknown options, wrong number of arguments, etc.) For example, diff -N, grep -Y or diff a b c will all result in $? being set to 2. This is and has been the practice since the early days of Unix in the 1970s.

The accepted answer explains what happens when a command is terminated by a signal. In brief, termination due to an uncaught signal results in exit status 128+[<signal number>. E.g., termination by SIGINT (signal 2) results in exit status 130.

Notes

  1. 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.

  2. 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.

查看更多
其实,你不懂
5楼-- · 2018-12-31 10:49

sysexits.h has a list of standard exit codes. It seems to date back to at least 1993 and some big projects like Postfix use it, so I imagine it's the way to go.

From the OpenBSD man page:

According to style(9), it is not good practice to call exit(3) with arbi- trary values to indicate a failure condition when ending a program. In- stead, the pre-defined exit codes from sysexits should be used, so the caller of the process can get a rough estimation about the failure class without looking up the source code.
查看更多
妖精总统
6楼-- · 2018-12-31 10:56

8 bits of the return code and 8 bits of the number of the killing signal are mixed into a single value on the return from 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" */
}

How are you determining the exit status? Traditionally, the shell only stores an 8-bit return code, but sets the high bit if the process was abnormally terminated.

$ sh -c 'exit 42'; echo $?
42
$ sh -c 'kill -SEGV $$'; echo $?
Segmentation fault
139
$ expr 139 - 128
11

If you're seeing anything other than this, then the program probably has a SIGSEGV signal handler which then calls exit normally, so it isn't actually getting killed by the signal. (Programs can chose to handle any signals aside from SIGKILL and SIGSTOP.)

查看更多
呛了眼睛熬了心
7楼-- · 2018-12-31 10:56

Programs return a 16 bit exit code. If the program was killed with a signal then the high order byte contains the signal used, otherwise the low order byte is the exit status returned by the programmer.

How that exit code is assigned to the status variable $? is then up to the shell. Bash keeps the lower 7 bits of the status and then uses 128 + (signal nr) for indicating a signal.

The only "standard" convention for programs is 0 for success, non-zero for error. Another convention used is to return errno on error.

查看更多
登录 后发表回答