Существуют ли стандартные коды состояния выхода в Linux?

308

Процесс считается завершенным правильно в Linux, если его состояние выхода было 0.

Я видел, что ошибки сегментации часто приводят к состоянию выхода 11, хотя я не знаю, является ли это просто соглашением, в котором я работаю (приложения, которые потерпели неудачу, как все, были внутренними) или стандартом.

Существуют ли стандартные коды выхода для процессов в Linux?

Натан Феллман
источник
6
если вы ищете «системный номер ошибки», возвращаемый системными функциями, посмотрите здесь на errno
marinara

Ответы:

86

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" */
}

Как вы определяете статус выхода? Традиционно оболочка хранит только 8-битный код возврата, но устанавливает старший бит, если процесс был ненормально завершен.

$ sh -c 'выход 42'; echo $?
42
$ sh -c 'kill -SEGV $$'; echo $?
Ошибка сегментации
139
$ expr 139 - 128
11

Если вы видите что-то кроме этого, то, вероятно, программа имеет SIGSEGVобработчик сигнала, который затем вызывается exitнормально, так что сигнал фактически не убивает. (Программы могут выбрать обработку любых сигналов, кроме SIGKILLи SIGSTOP.)

ephemient
источник
8
Учитывая то, как теперь возникает вопрос, это не самый полезный (и, следовательно, принятый) ответ.
Дэвид Дж.
332

Часть 1: Расширенное руководство по написанию сценариев Bash

Как всегда, в Advanced Bash Scripting Guide есть много полезной информации : (Это было связано с другим ответом, но с неканоническим URL).

1: Catchall для общих ошибок
2: Неправильное использование встроенных командных оболочек (согласно документации Bash)
126: Вызванная команда не может выполнить
127: «Команда не найдена»
128: Неверный аргумент для выхода
128 + n: Сигнал фатальной ошибки «n»
255: Выход состояние вне диапазона (выход принимает только целочисленные аргументы в диапазоне 0 - 255)

Часть 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 */
Schof
источник
5
Обратите внимание, что в некоторых разновидностях Unix некоторые команды используют состояние выхода 2, чтобы указать другие вещи. Например, многие реализации grep используют состояние выхода 2, чтобы указать ошибку, и используют состояние выхода 1, чтобы указать, что выбранные строки не были найдены.
NamshubWriter
3
На BSD есть справочная страница, обобщающая информацию из sysexits.h:man sysexits
georgebrock
6
Что сказал @NamshubWriter. Статус выхода 2 - это универсальный способ некорректного использования командной строки в утилитах Unix, причем не только в «некоторых вариантах Unix», но и в целом. Заголовок показано в этом ответе не отражает фактические соглашения, в настоящее время или когда она была написана в 1987 году
Alexis
АБС не "отличная". Пожалуйста, ознакомьтесь с предметом; не очень трудно найти критику.
tripleee
Но где настоящий официальный исходный код для sysexits.h? Человек страница все держит реферирование только прозу. Например, он ссылается, EX_OKно на самом деле не определяет его нормативным образом, как другие коды. Есть еще что-то, чего не хватает?
Гаррет Уилсон
71

'1' >>> Catchall для общих ошибок

'2' >>> Неправильное использование встроенных командных оболочек (согласно документации Bash)

'126' >>> Вызванная команда не может быть выполнена

'127' >>> "Команда не найдена"

«128» >>> Недопустимый аргумент для выхода

'128 + n' >>> Сигнал фатальной ошибки "n"

'130' >>> Сценарий прекращен с помощью Control-C

'255' >>> Выход из состояния вне диапазона

Это для Баш. Однако для других приложений существуют разные коды выхода.

выдаёт ошибку сегментации
источник
1
Похоже, вы оба ответили в одну и ту же минуту. Тиан должен был бы довольно быстро увидеть ваши ссылки и вставить их.
Натан Феллман
6
Обратите внимание, что 'control-C дает 130' соответствует '128 + n' для сигнала n; control-C генерирует сигнал SIGINT, который является сигналом 2.
Джонатан Леффлер
3
Это похоже на плагиат из АБС без указания авторства. (Мы можем сказать, потому что ABS содержит неверную или, по крайней мере, вводящую в заблуждение информацию.)
tripleee
4
Это зарезервированные коды выхода, согласно Advanced Bash-Scripting Guide . Это означает, что следует избегать этих значений для пользовательских параметров выхода .
ingyhere
53

Ни один из старых ответов не описывает правильное состояние выхода 2. Вопреки тому, что они утверждают, статус 2 - это то, что утилиты командной строки фактически возвращают при неправильном вызове. (Да, ответ может быть девять лет, иметь сотни голосов, и все же быть неправильным.)

Вот реальное, давнее соглашение о статусе выхода для нормального завершения, то есть не по сигналу:

  • Статус выхода 0: успех
  • Состояние выхода 1: «сбой», как определено программой
  • Состояние выхода 2: ошибка использования командной строки

Например, diffвозвращает 0, если сравниваемые файлы идентичны, и 1, если они различаются. В соответствии с давним соглашением, программы Unix возвращают состояние выхода 2 при неправильном вызове (неизвестные параметры, неправильное количество аргументов и т. Д.). Например diff -N, grep -Yили diff a b cвсе они приведут $?к установке на 2. Это и было практикой, так как Первые дни Unix в 1970-х.

Общепринятый ответ объясняет , что происходит , когда команда прерывается сигналом. Вкратце, завершение из-за необработанного сигнала приводит к состоянию выхода 128+[<signal number>. Например, завершение SIGINT( сигнал 2 ) приводит к состоянию выхода 130.

Ноты

  1. В нескольких ответах статус выхода 2 определяется как «Неправильное использование встроенных команд bash». Это применимо только тогда, когда bash (или скрипт bash) выходит со статусом 2. Считайте, что это особый случай неправильной ошибки использования.

  2. В sysexits.hупомянутом в самом популярном ответе статус выхода EX_USAGE(«ошибка использования командной строки») определен как 64. Но это не отражает реальность: я не знаю ни одной распространенной утилиты Unix, которая возвращает 64 при неправильном вызове (примеры приветствуются ). Внимательное прочтение исходного кода показывает, что это 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 
     *    clashing with oth­er exit statuses that random programs may 
     *    already return. 
    

    Другими словами, эти определения не отражают общепринятую практику того времени (1993 г.), но намеренно несовместимы с ней. Больше жалости.

Alexis
источник
Что нужна программа возвращение , когда он делает прекращение ручки ловя SIGINT / Ctrl-C? Еще 130? Имеет ли значение другая оболочка, кроме bash?
Гринго Суаве
1
Оболочка, которая выполняет программу, не имеет значения; теоретически процесс может выбрать выход с другим статусом в зависимости от своего родительского процесса, но я никогда не слышал о случае, когда это происходит.
Алексис
1
Если программа перехватывает SIGINT, очищается и в любом случае завершает работу, ее состояние будет таким, каким имеет смысл для программы. Например, moreсбросит режимы терминала и выйдет со статусом 0 (можно попробовать).
Алексис
1
Этот ответ подразумевает гораздо более высокий уровень стандартизации, чем на самом деле. Не существует надлежащей стандартизации значения значения 2, и тогда фактическая практика, как и следовало ожидать, весьма неоднозначна. Это правда, что многие инструменты возвращают 2 за неправильное использование, но не совсем ясно, что означает «неправильное использование», и многие другие не придерживаются этого соглашения.
tripleee
@tripleee "инструменты" тоже не очень хорошо определены! :-) Конечно, любой может написать программу командной строки, и она может вернуть что-либо вообще, но старые "утилиты командной строки Unix", которые были дольше, чем Linux, или содержимое GNU coreutils, вполне в соответствии с этим. Если вы думаете иначе, назовите некоторые инструменты в этой группе, которые не используют статус 2 таким образом. Кроме того, «неправильное использование» - это ваш термин (и я согласен, что это неопределенный термин); Я написал «Ошибка использования командной строки», которая довольно специфична: несуществующие или несовместимые параметры, неправильное количество аргументов, не являющихся параметрами, и т. Д.
alexis
25

Стандартных кодов выхода нет, кроме 0, означающего успех. Ненулевое также не обязательно означает неудачу.

stdlib.h определяет EXIT_FAILUREкак 1 и EXIT_SUCCESSкак 0, но это все.

11 на segfault интересен, так как 11 - это номер сигнала, который ядро ​​использует для уничтожения процесса в случае segfault. Вероятно, существует какой-то механизм, либо в ядре, либо в оболочке, который преобразует это в код выхода.

Крис Аргуин
источник
20

sysexits.h имеет список стандартных кодов выхода. Похоже, он датируется как минимум 1993 годом, и некоторые крупные проекты, такие как Postfix, используют его, так что я думаю, что это путь.

Со страницы руководства OpenBSD:

Согласно стилю (9), не рекомендуется вызывать exit (3) с произвольными значениями, чтобы указать состояние ошибки при завершении программы. Вместо этого следует использовать предопределенные коды выхода из sysexits, чтобы вызывающий процесс мог получить приблизительную оценку класса сбоев без поиска исходного кода.

источник
8

В первом приближении 0 - это успех, ненулевое значение - сбой, 1 - общий сбой, а все, что больше, - конкретный сбой. Помимо тривиальных исключений false и test, которые предназначены для получения 1 за успех, есть еще несколько исключений, которые я обнаружил.

Более реалистично, 0 означает успех или, возможно, сбой, 1 означает общий отказ или, может быть, успех, 2 означает общий отказ, если 1 и 0 оба используются для успеха, но, возможно, также и успех.

Команда diff дает 0, если сравниваемые файлы идентичны, 1, если они различаются, и 2, если двоичные файлы различны. 2 также означает неудачу. Команда less выдает 1 за неудачу, если только вы не предоставите аргумент, в этом случае она выходит из 0, несмотря на неудачу.

Команда more и команда spell дают 1 для сбоя, если сбой не является результатом отказа в доступе, несуществующего файла или попытки прочитать каталог. В любом из этих случаев они выходят из 0, несмотря на неудачу.

Затем команда expr выдает 1 для sucess, если только вывод не является пустой строкой или нулем, в этом случае 0 является sucess. 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 (нарушение сегмента), который отличается от кода возврата. Этот сигнал генерируется ядром в ответ на неправильный доступ к странице, что приводит к завершению программы. Список сигналов можно найти на странице справки по сигналам (запустите «сигнал человека»).

Даниэль Шулер
источник
1

Когда Linux возвращает 0, это означает успех. Все остальное означает сбой, у каждой программы есть свои коды выхода, поэтому было бы довольно долго перечислять их все ...!

Что касается кода ошибки 11, это действительно номер ошибки сегментации, в основном это означает, что программа получила доступ к области памяти, которая не была назначена.

Amadeus45
источник
1
Это всегда 11, потому что ядро ​​убивает его и назначает «значение выхода». Аналогично, другие типы неисправностей всегда будут иметь одинаковое значение выхода.
Алекс Гартрелл