Was sind die minimalen und maximalen Werte von Exit-Codes in Linux?

40

Wie lauten die Mindest- und Höchstwerte der folgenden Exit-Codes unter Linux:

  1. Der von einer ausführbaren Binärdatei zurückgegebene Exit-Code (z. B. ein C-Programm).
  2. Der Exit-Code, der von einem Bash-Skript zurückgegeben wurde (beim Aufruf exit).
  3. Der von einer Funktion zurückgegebene Exit-Code (beim Aufruf return). Ich denke das ist zwischen 0und 255.
user271801
quelle
Meinen Sie für Teil 3 die Rückkehr von einer Shell- Funktion? Das mag von der Shell abhängen, aber ich stelle fest, dass Bashs Handbuch besagt, dass " Exit-Status zwischen 0 und 255 liegen " und " Exit-Status von Shell-Builtins und zusammengesetzten Befehlen ebenfalls auf diesen Bereich beschränkt sind " return.
Toby Speight
Verwandt (hat Antworten auf die meisten Ihrer Fragen): Standard-Beendigungscode, wenn der Prozess beendet wird?
Stéphane Chazelas
@TobySpeight, das ist eine Einschränkung der bashShell. Einige andere Shells wie zshkönnen jeden vorzeichenbehafteten 32-Bit-Wert wie für zurückgeben exit. Einige mögen rcoder eskönnen Daten eines von ihnen unterstützten Typs (Skalar oder Liste) zurückgeben. Weitere Informationen finden Sie in den verknüpften Fragen und Antworten.
Stéphane Chazelas

Antworten:

74

Die an den _exit()/ exit_group()system-Aufruf übergebene Nummer (manchmal als Exit-Code bezeichnet) , um die Mehrdeutigkeit des Exit-Status zu vermeiden. Dies bezieht sich auch auf die Codierung des Exit-Codes oder der Signalnummer und zusätzliche Informationen, je nachdem, ob der Prozess abgebrochen oder normal beendet wurde ) ist vom Typ int, also auf Unix-ähnlichen Systemen wie Linux in der Regel eine 32-Bit-Ganzzahl mit Werten von -2147483648 (-2 31 ) bis 2147483647 (2 31 -1).

Jedoch auf allen Systemen, wenn die Eltern - Prozess (oder das Kind subreaper oder initwenn die Eltern gestorben ist ) verwendet die wait(), waitpid(), wait3(), wait4()Systemaufrufe , um es abzurufen, werden nur die unteren 8 Bits davon sind verfügbar (Werte von 0 bis 255 (2 8 - 1)).

Bei Verwendung der waitid()API (oder eines Signal-Handlers auf SIGCHLD) ist auf den meisten Systemen (und wie POSIX in der Ausgabe 2016 des Standards (siehe _exit()Spezifikation ) jetzt klarer vorschreibt ) die vollständige Nummer verfügbar (im si_statusFeld der zurückgegebenen Struktur) ). Unter Linux ist dies jedoch noch nicht der Fall, wodurch die Zahl mit der waitid()API ebenfalls auf 8 Bit gekürzt wird. Dies wird sich jedoch wahrscheinlich in Zukunft ändern.

Im Allgemeinen würden Sie nur wollen Werte verwenden 0 ( in der Regel bedeutet , Erfolg) auf nur 125, so viele Schalen - Werte über 128 in ihrer Verwendung $?Darstellung des Exit - Status die Signalnummer eines Prozesses zu kodieren , getötet zu werden , und 126 und 127 für Sonder Bedingungen.

Möglicherweise möchten Sie 126 bis 255 verwenden exit(), um dasselbe zu bedeuten wie für die Shell $?(wie bei einem Skript ret=$?; ...; exit "$ret"). Die Verwendung von Werten außerhalb von 0 -> 255 ist im Allgemeinen nicht sinnvoll. Das tun Sie im Allgemeinen nur, wenn Sie wissen, dass das übergeordnete Element die waitid()API auf Systemen verwendet, die nicht abgeschnitten sind und Sie zufällig den 32-Bit-Wertebereich benötigen. Beachten Sie exit(2048), dass dies beispielsweise von Eltern, die die traditionellen wait*()APIs verwenden , als Erfolg gewertet wird.

Mehr Infos unter:

Die Q & A sollte hoffentlich die meisten Ihre Fragen beantworten und klären , was gemeint ist mit Exit - Status . Ich werde noch ein paar Dinge hinzufügen:

Ein Prozess kann nur dann beendet werden, wenn er beendet wurde oder die _exit()/ exit_group()system-Aufrufe aufruft. Wenn Sie von main()in zurückkehren C, ruft die libc diesen Systemaufruf mit dem Rückgabewert auf.

Die meisten Sprachen haben eine exit()Funktion, die diesen Systemaufruf und den Wert, den sie annehmen, umschließt. (Beachten Sie, dass diese im Allgemeinen mehr tun als die Bereinigung durch die C- exit()Funktion, mit der die Stdio-Puffer geleert und die atexit()Hooks ausgeführt werden ...)

Das ist zumindest der Fall bei:

$ strace -e exit_group awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group mawk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group busybox awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ echo | strace -e exit_group sed 'Q1234'
exit_group(1234)                        = ?
$ strace -e exit_group perl -e 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group python -c 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group expect -c 'exit 1234'
exit_group(1234)                        = ?
$ strace -e exit_group php -r 'exit(1234);'
exit_group(1234)                        = ?
$ strace -e exit_group zsh -c 'exit 1234'
exit_group(1234)

Sie sehen gelegentlich einige, die sich beschweren, wenn Sie einen Wert außerhalb von 0-255 verwenden:

$ echo 'm4exit(1234)' | strace -e exit_group m4
m4:stdin:1: exit status out of range: `1234'
exit_group(1)                           = ?

Einige Muscheln beschweren sich, wenn Sie einen negativen Wert verwenden:

$ strace -e exit_group dash -c 'exit -1234'
dash: 1: exit: Illegal number: -1234
exit_group(2)                           = ?
$ strace -e exit_group yash -c 'exit -- -1234'
exit: `-1234' is not a valid integer
exit_group(2)                           = ?

POSIX lässt das Verhalten undefiniert, wenn der an das exitSpecial Builtin übergebene Wert außerhalb von 0 -> 255 liegt.

Einige Shells zeigen unerwartetes Verhalten, wenn Sie Folgendes tun:

  • bash(und mkshnicht, pdkshworauf es basiert) setzt voraus, dass der Wert auf 8 Bits gekürzt wird:

    $ strace -e exit_group bash -c 'exit 1234'
    exit_group(210)                         = ?
    

    Wenn Sie also in diesen Shells mit einem Wert außerhalb von 0-255 beenden möchten, müssen Sie Folgendes tun:

    exec zsh -c 'exit -- -12345'
    exec perl -e 'exit(-12345)'
    

    Das ist ein weiterer Befehl in dem gleichen Prozess ausführen, kann den Systemaufruf mit dem Wert rufen Sie wollen.

  • Wie bereits in den anderen Fragen und ksh93Antworten erwähnt, hat es das seltsamste Verhalten für Exit-Werte von 257 bis 256 + max_signal_number, wobei exit_group()es sich selbst mit dem entsprechenden Signal beendet, anstatt aufzurufen¹.

    $ ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    zsh: suspended (signal)  ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    

    und schneidet sonst die Zahl wie bash/ ab mksh.


¹ Das wird sich wahrscheinlich in der nächsten Version ändern. Jetzt, da die Entwicklung von ksh93als Gemeinschaftsanstrengung außerhalb von AT & T übernommen wurde, wird dieses Verhalten, obwohl es irgendwie von POSIX gefördert wird, rückgängig gemacht

Stéphane Chazelas
quelle
2
Wissen Sie, ob es Diskussionen zur Implementierung des vollständigen Exit-Codes si_statusfür Linux gibt?
Ruslan
2
@ Ruslan, nicht mehr als die austingroupbugs.net/view.php?id=594#c1318 (von Eric Blake (RedHat)) bei dem Link, den ich gegeben habe
Stéphane Chazelas
1
msgstr "ist vom Typ int, also eine 32 - Bit - Ganzzahl". Linux garantiert wirklich, dass ein int immer 32bit sein wird? Selbst wenn Sie auf einigen dieser winzigen Mikrocontroller laufen? Das kommt mir wirklich komisch vor. POSIX bestimmt nicht.
Voo
@Voo, diese winzigen Mikrocontroller können Linux nicht ausführen. Während für C intmindestens 16 Bit erforderlich sind , muss für POSIX mehr oder weniger mindestens 32 Bit angegeben werden, und für Programmierumgebungen muss uint32_t angegeben werden . Ich weiß nicht, ob Linux eine Programmierumgebung unterstützt, in der Ints alles andere als 32 Bit sind. Ich bin nie auf eine gestoßen.
Stéphane Chazelas
1
Unter einem POSIX-kompatiblen Betriebssystem erhalten Sie möglicherweise den vollständigen 32-Bit-Exit-Code in der aktuellen Version der Bourne Shell (siehe: schillix.sourceforge.net/man/man1/bosh.1.html
schily
12

Das Minimum ist 0, und das ist der Erfolgswert. Alle anderen sind Fehlschläge. Das Maximum ist 255auch bekannt als -1.

Diese Regeln gelten sowohl für Skripte und andere ausführbare Dateien als auch für Shell-Funktionen.

Größere Werte ergeben modulo 256.

Tomasz
quelle
2
Um genau zu sein, wird in einigen Bourne-ähnlichen Shells (aber nicht bashoder in anderen am häufigsten verwendeten) der an das exitBuiltin übergebene Exit-Code nicht als Modulo-256 behandelt und verursacht stattdessen einen Fehler. (Zum Beispiel ist das Common exit -1eigentlich kein tragbares Äquivalent zu den exit 255meisten Shells). Und ob exit(-1)auf der C-Ebene gleichbedeutend mit exit(255)ist , ist ein Detail, das de facto sicher funktioniert, sich jedoch auf das implementierungsdefinierte Verhalten stützt (obwohl dies bei modernen Systemen, die Sie wahrscheinlich in der Praxis verwenden, kein Problem darstellt).
mtraceur
Soweit ich weiß, begrenzt nur ksh93 den exit(1)Parameter auf 8 Bits.
Schily
6

Das sieht so einfach aus, aber oh, das Leid.

Die C-Sprache (und danach die meisten anderen Sprachen direkt oder indirekt) erfordert, dass die Rückkehr von maindem Aufruf exitmit dem gleichen Argument wie der Rückgabewert äquivalent ist. Dies ist eine Ganzzahl (der Rückgabetyp ist sehr eindeutig int), daher wäre der Bereich im Prinzip INT_MINzu INT_MAX.

POSIX gibt jedoch an, dass nur die untersten 8 übergebenen Bits exiteinem wartenden übergeordneten Prozess zur Verfügung gestellt werden sollen, wörtlich so, als wäre es "status & 0xFF" .
In der Praxis ist der Exit-Code also eine (noch vorzeichenbehaftete) Ganzzahl, von der nur die niedrigsten 8 Bits gesetzt sind.

Das Minimum ist also -128 und das Maximum 127 . Warte, das stimmt nicht. Es wird 0 bis 255 sein.

Aber leider kann es natürlich nicht so einfach sein . In der Praxis macht Linux (oder besser Bash) das anders . Der gültige Bereich der Rückkehrcodes liegt zwischen 0 und 255 (dh ohne Vorzeichen).

Um Verwechslungen zu vermeiden, ist es wahrscheinlich eine gute Idee, einfach davon auszugehen, dass die Rückkehrcodes nicht signiert sind, und alles, was Sie zurückerhalten, waitin nicht signiert umzuwandeln. Auf diese Weise stimmt es mit dem überein, was Sie in einer Shell sehen. Da die obersten Bits (einschließlich des höchstwertigen) gelöscht werden, ist dies nicht einmal "falsch", da die tatsächlichen Werte, obwohl technisch signiert, immer ohne Vorzeichen sind (da das Vorzeichenbit niemals gesetzt ist).
Es hilft auch, den allgemeinen Fehler beim Vergleichen eines Exit-Codes mit zu vermeiden -1, der aus irgendeinem seltsamen Grund selbst dann nicht zu erscheinen scheint, wenn ein Programm mit beendet wird -1(raten Sie mal, warum!).

Über Ihren letzten Punkt, von einer Funktion zurückzukehren, wenn diese Funktion zufällig ist main, dann siehe oben. Ansonsten hängt es vom Rückgabetyp der Funktion ab, es kann im Prinzip alles (einschließlich void) sein.

Damon
quelle
Sie haben vor 1989 Recht gehabt, als waitid()vorgestellt wurde.
Schily
@schily: Weißt du nicht, was du meinst? waitid()macht genau das gleiche, etwas anders. Es wartet auf eine bestimmte ID oder einem Faden, und es schreibt Ergebnisse der Spitz zu siginfo_tStruktur , wo si_statusist int(so ... unterzeichnet , nur das gleiche). Trotzdem exit()passiert nur die untersten 8 Bits, also ... absolut das Gleiche unter der Haube.
Damon
exit()Übergibt alle 32 Bits des Parameters an den Kernel und waitid()gibt alle 32 Bits des Exit-Codes zurück. Vielleicht haben Sie unter Linux nachgesehen, wo es niemanden interessiert, Fehler zu beheben. Wenn Sie mir nicht glauben, überprüfen Sie es auf einem POSIX-kompatiblen Betriebssystem ...
schily
@schily: Wenn das stimmt (ich glaube es nicht, aber trotzdem), dann ist Linux kaputt . Bitte lesen Sie die mit der Antwort verknüpfte POSIX-Spezifikation exit, insbesondere die zweite Zeile unter "Beschreibung", die besagt: "obwohl einem wartenden übergeordneten Prozess nur die niedrigstwertigen 8 Bits (dh Status & 0377) zur Verfügung stehen sollen " . So funktioniert eine konforme Implementierung - unterste 8 Bit, nicht 32. Haben Sie eine Referenz für die Weitergabe von 32 Bit?
Damon
Ich dachte, ich erwähne, dass Linux kaputt ist. Schlimmer noch: Die Linux-Kernel-Leute weigern sich, Fehler zu beheben. Wenn Sie den POSIX-Standard lesen, werden Sie feststellen, dass die 1995-Version (SUSv1) die ursprünglich von SVr4 1989 eingeführte Funktion korrekt erklärt und dass neuere Versionen (z. B. SUSv7tc2) des Standards dies sogar explizit erklären waitid()und die siginfo_tStruktur an den SIGCHLDHandler zurückgeben alle 32 Bits des exit()Parameters.
Schily
2
  1. Der von einer ausführbaren Binärdatei zurückgegebene Exit-Code (z. B. ein C-Programm).
  2. Der von einem Bash-Skript zurückgegebene Exit-Code (beim Aufrufen von exit).

Exit-Codes für jeden Prozess - ob es sich um eine binäre ausführbare Datei, ein Shell-Skript oder etwas anderes handelt - reichen von 0 bis 255. Es ist möglich, einen größeren Wert an zu übergeben exit(), aber nur die unteren 8 Bits des Status werden zur Verfügung gestellt andere Prozesse durch wait().

  1. Der von einer Funktion zurückgegebene Exit-Code (beim Aufruf von return). Ich denke das liegt zwischen 0 und 255.

Die AC-Funktion kann als Rückgabe fast jedes Typs deklariert werden. Die Grenzen seines Rückgabewerts werden vollständig von diesem Typ bestimmt: beispielsweise -128 bis 127 für eine Funktionsrückgabe signed charoder 0 bis 4,2 Milliarden für eine Funktionsrückgabe unsigned intoder eine beliebige Gleitkommazahl bis einschließlich infeiner Funktionsrückgabe double. Und das zählt nicht die nicht-numerischen Typen wie void *oder struct...

duskwuff
quelle