Czy są jakieś standardowe kody stanu wyjścia w systemie Linux?


308

Uważa się, że proces zakończył się poprawnie w systemie Linux, jeśli jego kodem zakończenia było 0.

Widziałem, że błędy segmentacji często skutkują statusem wyjścia 11, choć nie wiem, czy to po prostu konwencja, w której pracuję (aplikacje, które zawiodły, wszystkie były wewnętrzne), czy standard.

Czy istnieją standardowe kody wyjścia dla procesów w systemie Linux?


6
jeśli szukasz czegoś zwanego „numerem błędu systemowego” zwracanego przez funkcje systemowe, spójrz tutaj na errno
marinara

Odpowiedzi:


86

8 bitów kodu powrotu i 8 bitów liczby sygnału zabijania są mieszane w jedną wartość po powrocie z 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" */
}

Jak określasz status wyjścia? Tradycyjnie powłoka przechowuje tylko 8-bitowy kod powrotu, ale ustawia wysoki bit, jeśli proces został nieprawidłowo zakończony.

$ sh -c 'exit 42'; echo $?
42
$ sh -c 'kill -SEGV $$'; echo $?
Błąd segmentacji
139
139-138 USD
11

Jeśli widzisz coś innego niż to, program prawdopodobnie ma SIGSEGVmoduł obsługi sygnału, który następnie wywołuje exitnormalnie, więc tak naprawdę nie zostaje zabity przez sygnał. (Programy mogą obsługiwać wszelkie sygnały oprócz SIGKILLi SIGSTOP.)


8
Biorąc pod uwagę sposób, w jaki teraz pojawia się pytanie, nie wydaje się to najbardziej użyteczną (i w ten sposób akceptowaną) odpowiedzią.
David J.

332

Część 1: Podręcznik zaawansowanego skryptu Bash

Jak zawsze, Advanced Bash Scripting Guide ma świetne informacje : (To było połączone w innej odpowiedzi, ale z niekanonicznym adresem URL).

1: Catchall dla błędów ogólnych
2: Niewłaściwe użycie wbudowanych powłok (zgodnie z dokumentacją Bash)
126: Wywołane polecenie nie może wykonać
127: „polecenie nie znaleziono”
128: Nieprawidłowy argument wyjścia
128 + n: Fatalny sygnał błędu „n”
255: Wyjście status poza zakresem (wyjście przyjmuje tylko argumenty całkowite z zakresu 0 - 255)

Część 2: sysexits.h

Referencje ABSG sysexits.h.

W systemie 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
Zauważ, że w niektórych odmianach Uniksa niektóre polecenia używają statusu wyjścia 2, aby wskazać inne rzeczy. Na przykład wiele implementacji grep używa statusu wyjścia 2, aby wskazać błąd, a statusu wyjścia 1 oznacza, że ​​nie znaleziono wybranych linii.
NamshubWriter,

3
Na temat BSD znajduje się strona podręcznika podsumowująca informacje z sysexits.h:man sysexits
georgebrock

6
Co powiedział @NamshubWriter. Status wyjścia 2 to uniwersalny sposób na niepoprawne użycie wiersza poleceń w narzędziach uniksowych, nie tylko w „niektórych odmianach unixa”, ale ogólnie. Nagłówek pokazany w tej odpowiedzi nie odzwierciedla faktycznych konwencji, ani teraz, ani kiedy został napisany w 1987 r.
Alexis

ABS nie jest „świetny”. Proszę przeczytać na ten temat; krytyka nie jest trudna.
tripleee

Ale gdzie jest prawdziwy oficjalny kod źródłowy sysexits.h? Strona człowiek każdy trzyma odsyłania tylko proza. Na przykład odwołuje się, EX_OKale tak naprawdę nie definiuje go w sposób normatywny, jak inne kody. Czy brakuje czegoś więcej?
Garret Wilson,

71

„1” >>> Catchall dla błędów ogólnych

„2” >>> Niewłaściwe użycie wbudowanych powłok (zgodnie z dokumentacją Bash)

„126” >>> Wywołane polecenie nie może zostać wykonane

„127” >>> „Nie znaleziono polecenia”

„128” >>> Niepoprawny argument do wyjścia

„128 + n” >>> Sygnał błędu krytycznego „n”

„130” >>> Skrypt zakończony przez Control-C

„255” >>> Wyjdź ze statusu poza zakresem

To jest bash. Jednak w przypadku innych aplikacji istnieją różne kody wyjścia.


1
Wygląda na to, że oboje odpowiedzieliście w tej samej minucie. Tian musiałby być bardzo szybki, aby zobaczyć twoje linki i wkleić je.
Nathan Fellman

6
Należy zauważyć, że „control-C daje 130” jest zgodne z „128 + n” dla sygnału n; control-C generuje SIGINT, który jest sygnałem 2.
Jonathan Leffler

3
Wydaje się, że jest to plagiat z ABS bez przypisania. (Możemy to stwierdzić, ponieważ ABS zawiera nieprawidłowe lub przynajmniej wprowadzające w błąd informacje.)
tripleee 10.10.16

4
Są to ZREZERWOWANE kody wyjścia, zgodnie z przewodnikiem Advanced Bash-Scripting Guide . Oznacza to, że tych wartości należy zatem unikać w przypadku parametrów wyjścia określonych przez użytkownika .
ingyhere

53

Żadna ze starszych odpowiedzi nie opisuje poprawnie wyjścia 2. W przeciwieństwie do tego, co twierdzą, status 2 jest tym, co narzędzia wiersza poleceń faktycznie zwracają, gdy są wywoływane nieprawidłowo. (Tak, odpowiedź może mieć dziewięć lat, mieć setki pozytywnych opinii i nadal być w błędzie).

Oto prawdziwa, długotrwała konwencja statusu wyjścia dla normalnego zakończenia, tzn. Nie przez sygnał:

  • Wyjdź ze stanu 0: sukces
  • Wyjdź ze stanu 1: „awaria”, zgodnie z definicją programu
  • Wyjdź ze stanu 2: błąd użycia wiersza polecenia

Na przykład diffzwraca 0, jeśli porównywane pliki są identyczne, a 1, jeśli się różnią. Zgodnie z wieloletnią konwencją programy uniksowe zwracają status wyjścia 2, gdy są niepoprawnie wywoływane (nieznane opcje, zła liczba argumentów itp.) Na przykład diff -N, grep -Ylub diff a b cwszystkie spowodują $?ustawienie na 2. Jest to i było praktyką, ponieważ wczesne dni Uniksa w latach 70.

Odpowiedź Zaakceptowany wyjaśnia, co się dzieje, gdy polecenie jest zakończony przez sygnał. W skrócie, zakończenie z powodu nieprzechwyconego sygnału powoduje status wyjścia 128+[<signal number>. Np. Zakończenie przez SIGINT( sygnał 2 ) powoduje status wyjścia 130.

Notatki

  1. Kilka odpowiedzi definiuje status wyjścia 2 jako „Niewłaściwe użycie wbudowanych bashów”. Ma to zastosowanie tylko wtedy, gdy bash (lub skrypt bash) kończy się ze statusem 2. Rozważ to szczególny przypadek nieprawidłowego użycia błędu.

  2. W sysexits.h, wspomnianym w najpopularniejszej odpowiedzi , status wyjścia EX_USAGE(„błąd użycia wiersza poleceń”) jest zdefiniowany jako 64. Ale to nie odzwierciedla rzeczywistości: nie znam żadnego wspólnego narzędzia uniksowego, które zwraca 64 przy nieprawidłowym wywołaniu (mile widziane przykłady ). Uważne czytanie kodu źródłowego ujawnia, że sysexits.hjest ono raczej aspiracyjne niż odzwierciedleniem prawdziwego użycia:

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

    Innymi słowy, definicje te nie odzwierciedlają powszechnej wówczas praktyki (1993), ale celowo były z nią niezgodne. Więcej szkoda.


Co powinien powrót programu, gdy robi zakończenie uchwytu łapiąc SIGINT / CTRL-C? Nadal 130? Czy użycie innej powłoki oprócz bash ma znaczenie?
Gringo Suave,

1
Powłoka wykonująca program jest nieistotna; proces może teoretycznie wybrać wyjście z innym statusem, zależnie od procesu macierzystego, ale nigdy nie słyszałem o przypadku, w którym tak się dzieje.
Alexis

1
Jeśli program łapie SIGINT, czyści i wychodzi i tak, status ma znaczenie dla programu. Na przykład morezresetuje tryby terminalu i wyjdzie ze statusem 0 (możesz spróbować).
Alexis

1
Ta odpowiedź implikuje znacznie wyższy stopień standaryzacji niż w rzeczywistości. Nie ma odpowiedniej standaryzacji znaczenia wartości 2, a rzeczywista praktyka jest wtedy przewidywalnie bardzo mieszana. To prawda, że ​​wiele narzędzi zwraca 2 za niewłaściwe użycie, ale nie jest dokładnie zdefiniowane, co oznacza „niewłaściwe użycie”, a wiele innych nie przestrzega tej konwencji.
tripleee

@tripleee „narzędzia” też nie są dobrze zdefiniowane! :-) Jasne, każdy może napisać program wiersza poleceń i może w ogóle cokolwiek zwrócić, ale stare szkolne „narzędzia wiersza poleceń Unixa”, które były dostępne dłużej niż Linux, lub zawartość jądra GNU, są dość konsekwentnie w tym. Jeśli uważasz inaczej, podaj w tej grupie narzędzia, które nie używają w ten sposób statusu 2. Również „niewłaściwe użycie” to twój termin (i zgadzam się, że jest to termin niejasny); Napisałem „błąd użycia wiersza poleceń”, który jest dość specyficzny: nieistniejące lub niezgodne opcje, zła liczba argumentów nieopartych na opcjach itp.
Alexis

25

Nie ma standardowych kodów wyjścia, poza 0, co oznacza sukces. Niezerowa również niekoniecznie oznacza awarię.

stdlib.h definiuje EXIT_FAILUREjako 1 i EXIT_SUCCESSjako 0, ale o to chodzi.

11 na segfault jest interesujące, ponieważ 11 to numer sygnału, którego jądro używa do zabicia procesu w przypadku wystąpienia segfault. Prawdopodobnie istnieje jakiś mechanizm, albo w jądrze, albo w powłoce, który tłumaczy to na kod wyjścia.


20

sysexits.h ma listę standardowych kodów wyjścia. Wygląda na to, że datuje się na co najmniej 1993 r., A niektóre duże projekty, takie jak Postfix, używają go, więc wyobrażam sobie, że tak należy.

Ze strony podręcznika OpenBSD:

Zgodnie ze stylem (9), dobrą praktyką jest wywoływanie exit (3) z dowolnymi wartościami, aby wskazać stan awarii podczas kończenia programu. Zamiast tego należy użyć predefiniowanych kodów wyjścia z sysexits, aby wywołujący proces mógł uzyskać przybliżoną ocenę klasy awarii bez wyszukiwania kodu źródłowego.

8

W pierwszym przybliżeniu 0 oznacza powodzenie, niezerowe oznacza awarię, przy czym 1 oznacza awarię ogólną, a wszystko większe niż jedno oznacza awarię konkretną. Oprócz trywialnych wyjątków fałszowania i testowania, które są zaprojektowane tak, aby dać 1 dla powodzenia, znalazłem kilka innych wyjątków.

Bardziej realistycznie, 0 oznacza sukces, a może porażkę, 1 oznacza ogólną porażkę, a może sukces, 2 oznacza ogólną porażkę, jeśli 1 i 0 są użyte zarówno do sukcesu, ale może również sukcesu.

Polecenie diff daje 0, jeśli porównywane pliki są identyczne, 1, jeśli się różnią, i 2, jeśli pliki binarne są różne. 2 oznacza także awarię. Komenda less daje 1 za niepowodzenie, chyba że nie podasz argumentu, w którym to przypadku kończy 0, pomimo niepowodzenia.

Komenda more i komenda spell dają 1 za niepowodzenie, chyba że niepowodzenie jest wynikiem odmowy dostępu, nieistniejącego pliku lub próby odczytania katalogu. W każdym z tych przypadków wychodzą one z wartości 0 pomimo niepowodzenia.

Następnie polecenie expr daje 1 dla powodzenia, chyba że wynikiem jest pusty ciąg znaków lub zero, w którym to przypadku 0 oznacza powodzenie. 2 i 3 są porażką.

Są też przypadki, w których sukces lub porażka są niejednoznaczne. Gdy grep nie znajdzie wzorca, kończy 1, ale kończy 2 dla prawdziwej awarii (np. Odmowa zgody). Klist wychodzi również z 1, gdy nie może znaleźć biletu, chociaż tak naprawdę nie jest to więcej niż awaria niż wtedy, gdy grep nie znajduje wzorca lub gdy masz pusty katalog.

Tak więc, niestety, moce uniksowe, które wydają się nie wymuszać żadnego logicznego zestawu reguł, nawet w przypadku bardzo często używanych plików wykonywalnych.


Chciałem też zwrócić uwagę na zachowanie diffa. wget ma również szczegółowe błędy (np. 6 w przypadku niepowodzenia uwierzytelnienia), ale potem używają 1 = błąd ogólny, 2..n = błąd specyficzny
PypeBros

5

Programy zwracają 16-bitowy kod wyjścia. Jeśli program został zabity sygnałem, wówczas bajt wysokiego rzędu zawiera używany sygnał, w przeciwnym razie bajt niskiego rzędu to status wyjścia zwracany przez programistę.

Jak ten kod wyjścia jest przypisany do zmiennej statusu $? zależy od powłoki. Bash zachowuje 7 niższych bitów statusu, a następnie używa 128 + (nr sygnału) do wskazania sygnału.

Jedyną „standardową” konwencją dla programów jest 0 dla sukcesu, a niezerowa dla błędu. Inną stosowaną konwencją jest zwracanie errno po błędzie.


3

Standardowe kody wyjścia Unix są zdefiniowane przez sysexits.h, jak wspomniano w innym plakacie. Te same kody wyjścia są używane przez biblioteki przenośne, takie jak Poco - oto ich lista:

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

Sygnał 11 jest sygnałem SIGSEGV (naruszenie segmentu), który różni się od kodu powrotu. Jądro generuje ten sygnał w odpowiedzi na zły dostęp do strony, co powoduje zakończenie programu. Listę sygnałów można znaleźć na stronie man sygnału (uruchom „man signal”).


1

Kiedy Linux zwraca 0, oznacza to sukces. Wszystko inne oznacza awarię, każdy program ma własne kody zakończenia, więc lista wszystkich z nich byłaby dość długa ...!

W przypadku kodu błędu 11 jest to rzeczywiście numer błędu segmentacji, co w większości oznacza, że ​​program uzyskał dostęp do pamięci, która nie została przypisana.


1
Jest zawsze 11, ponieważ jądro go zabija i przypisuje „wartość wyjścia”. Podobnie, inne typy Błędów zawsze otrzymają tę samą wartość wyjściową.
Alex Gartrell,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.