Wenn ein Prozess mit einem handhabbaren Signal beendet wird, wie SIGINT
oder SIGTERM
aber nicht, wie lautet der Beendigungscode des Prozesses?
Was ist mit unbehandelbaren Signalen SIGKILL
?
Nach allem, was ich sagen kann, SIGINT
führt das Beenden eines Prozesses wahrscheinlich zu Exit-Code 130
. Aber würde das je nach Kernel- oder Shell-Implementierung variieren?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
Ich bin mir nicht sicher, wie ich die anderen Signale testen würde ...
$ ./myScript &
$ killall myScript
$ echo $?
0 # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0 # same problem
kill
signals
exit
exit-status
Cory Klein
quelle
quelle
killall myScript
Arbeiten, daher ist die Rückgabe des killall (und nicht des Skripts!) 0. Sie könnten einkill -x $$
[x als Signalnummer setzen und $$ normalerweise durch die Shell auf die PID des Skripts erweitern (funktioniert in sh, bash, ...)] innerhalb des Skripts und testen Sie dann, was der Ausgangskern war.&
). Senden Sie das Signal von einem anderen Shell-Prozess (in einem anderen Terminal), und verwenden Sie es,$?
nachdem myScript beendet wurde.Antworten:
Prozesse können den
_exit()
Systemaufruf (unter Linux, siehe auchexit_group()
) mit einem Integer-Argument aufrufen , um einen Exit-Code an das übergeordnete Element zu melden. Obwohl es eine ganze Zahl ist, werden nur die 8 niedrigstwertigen Bits an die Mutter verfügbar sind (Ausnahme das ist , wenn unter Verwendung vonwaitid()
in den übergeordneten oder Handler auf SIGCHLD diesen Code abgerufen werden , wenn auch nicht auf Linux).Das übergeordnete Element führt in der Regel ein
wait()
oder auswaitpid()
, um den Status des untergeordneten Elements als Ganzzahl abzurufen (obwohl auch einewaitid()
etwas andere Semantik verwendet werden kann).Unter Linux und die meisten Unix - Varianten, wenn der Prozess normal beendet, die Bits 8 bis 15 der Statusnummer wird den Exit - Code enthält , wie sie weitergegeben
exit()
. Wenn nicht, dann enthalten die 7 niedrigstwertigen Bits (0 bis 6) die Signalnummer und Bit 7 wird gesetzt, wenn ein Kern ausgegeben wurde.perl
ist$?
beispielsweise enthält die Zahl ist, wie sie durchwaitpid()
:Bourne-ähnliche Shells geben auch den Exit-Status des letzten Ausführungsbefehls in ihrer eigenen
$?
Variablen an. Es enthält jedoch nicht direkt die Zahl, die von zurückgegeben wurdewaitpid()
, sondern eine Transformation darauf und unterscheidet sich zwischen den Shells.Allen Shells ist gemeinsam, dass sie
$?
die niedrigsten 8 Bits des Exit-Codes (die Nummer, an die übergeben wirdexit()
) enthalten, wenn der Prozess normal beendet wird.Der Unterschied besteht darin, dass der Prozess durch ein Signal beendet wird. In allen Fällen, und das ist für POSIX erforderlich, ist die Zahl größer als 128. POSIX gibt nicht an, wie hoch der Wert sein darf. In der Praxis
$?
enthalten die untersten 7 Bits aller mir bekannten Bourne-ähnlichen Shells die Signalnummer. Aber won
ist die Signalnummer,in Asche, zsh, pdksh, schlag, die Bourne - Shell
$?
ist128 + n
. Was das bedeutet , ist , dass in den Schalen, wenn Sie eine bekommen$?
von129
, Sie wissen nicht, ob es daran , dass der Prozess mit verlassen ,exit(129)
oder ob es durch das Signal getötet wurde1
(HUP
auf den meisten Systemen). Das Grundprinzip ist jedoch, dass Shells, wenn sie sich selbst beenden, standardmäßig den Beendigungsstatus des zuletzt beendeten Befehls zurückgeben. Wenn Sie sicherstellen$?
, dass der Wert niemals größer als 255 ist, können Sie einen konsistenten Beendigungsstatus festlegen:ksh93
,$?
Ist256 + n
. Das bedeutet, dass Sie aus einem Wert von$?
zwischen einem getöteten und einem nicht getöteten Prozess unterscheiden können. Neuere Versionen von beenden sich mit demselben Signalksh
, wenn sie$?
größer als 255 waren, um dem übergeordneten Element denselben Beendigungsstatus melden zu können. Das klingt zwar nach einer guten Idee, bedeutet aber, dassksh
ein zusätzlicher Core-Dump generiert wird (der andere wird möglicherweise überschrieben), wenn der Prozess durch ein Core-Generierungssignal beendet wurde:Man könnte sogar sagen, dass es einen Fehler gibt,
ksh93
der sich selbst tötet, selbst wenn$?
erreturn 257
von einer Funktion ausgeführt wird:yash
.yash
bietet einen Kompromiss. Es kehrt zurück256 + 128 + n
. Das heißt, wir können auch zwischen einem abgebrochenen und einem ordnungsgemäß abgebrochenen Prozess unterscheiden. Und beim Verlassen meldet es sich,128 + n
ohne sich selbst umbringen zu müssen, und welche Nebenwirkungen es haben kann.Um das Signal aus dem Wert von zu erhalten
$?
, können Sie auf tragbare Weise Folgendes verwendenkill -l
:(aus Gründen der Portabilität sollten Sie niemals Signalnummern verwenden, sondern nur Signalnamen)
An den Nicht-Bourne-Fronten:
csh
/tcsh
undfish
wie die Bourne-Shell, mit der Ausnahme, dass sich der Status in$status
statt befindet$?
(beachten Sie, dass dieszsh
auch$status
für die Kompatibilität mitcsh
(zusätzlich zu$?
) festgelegt ist).rc
: der Exit-Status ist auch in$status
, aber wenn diese Variable von einem Signal getötet wird, enthält sie den Namen des Signals (wiesigterm
odersigill+core
wenn ein Core generiert wurde) anstelle einer Zahl, was ein weiterer Beweis für das gute Design dieser Shell ist .es
. Der Exit-Status ist keine Variable. Wenn Sie sich darum kümmern, führen Sie den Befehl wie folgt aus:die wird eine Nummer
sigterm
odersigsegv+core
wie in zurückgebenrc
.Vielleicht für die Vollständigkeit, sollten wir erwähnen ,
zsh
‚s$pipestatus
undbash
‘ s -$PIPESTATUS
Arrays , die den Exit - Status der Komponenten der letzten Pipeline enthalten.Und auch der Vollständigkeit
return
halber , wenn es um Shell-Funktionen und Quelldateien geht, kehren Funktionen standardmäßig mit dem Exit-Status des letzten Befehlslaufs zurück, können aber mit dem eingebauten Befehl auch explizit einen Return-Status setzen. Und wir sehen hier einige Unterschiede:bash
undmksh
(seit R41 wird anscheinend absichtlich eine Regression ^ Wchange eingeführt ) wird die Zahl (positiv oder negativ) auf 8 Bits abgeschnitten. So zum Beispielreturn 1234
wird festgelegt$?
auf210
,return -- -1
wird eingestellt$?
auf 255.zsh
undpdksh
(und andere Ableitungen alsmksh
) erlauben jede vorzeichenbehaftete 32-Bit-Dezimalzahl (-2 31 bis 2 31 -1) (und kürzen die Zahl auf 32 Bit ).ash
undyash
erlaube eine beliebige positive ganze Zahl von 0 bis 2 31 -1 und gebe einen Fehler für eine beliebige Zahl davon zurück.ksh93
Fürreturn 0
diereturn 320
Einstellung$?
wie sie ist, aber für alles andere, kürzen Sie auf 8 Bits. Beachten Sie, wie bereits erwähnt, dass sich das Zurückgeben einer Zahl zwischen 256 und 320ksh
beim Beenden selbst töten kann.rc
undes
erlauben, alles auch Listen zurückzugeben.Beachten Sie auch, dass einige Shells auch spezielle Werte von
$?
/ verwenden$status
, um einige Fehlerzustände zu melden, die nicht den Beendigungsstatus eines Prozesses darstellen, z. B.127
oder126
für einen Befehl, der nicht gefunden oder nicht ausführbar ist (oder einen Syntaxfehler in einer Quelldatei) ...quelle
an exit code to their parent
undto get the *status* of their child
. Sie haben den Schwerpunkt auf "Status" gelegt. Istexit code
und*status*
das gleiche? Fall ja, woher kommen zwei Namen? Falls nicht gleich, könnten Sie die Definition / Referenz des Status angeben?exit()
. Der Exit-Status : Die Nummer, anhandwaitpid()
derer der Exit-Code, die Signalnummer und die Frage, ob ein Core gelöscht wurde, ermittelt werden. Und die Zahl, die einige Shells in einer ihrer speziellen Variablen ($?
,$status
) zur Verfügung stellen, ist eine solche Transformation des Exit-Status , die den Exit-Code für den Fall einer normalen Beendigung enthält, aber auch Signalinformationen enthält, wenn Der Prozess wurde abgebrochen (dieser Prozess wird im Allgemeinen auch als Exit-Status bezeichnet ). Das ist alles in meiner Antwort erklärt.> 128
Teil: "Der Beendigungsstatus eines Befehls, der abgebrochen wurde, weil er ein Signal empfangen hat, soll als größer als 128 gemeldet werden." pubs.opengroup.org/onlinepubs/9699919799/utilities/…[email protected]
(ab dem 06.05.2015) oderXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Wenn ein Prozess beendet wird, gibt er einen ganzzahligen Wert an das Betriebssystem zurück. Bei den meisten Unix-Varianten wird dieser Wert modulo 256 genommen: Alles außer den niederwertigen Bits wird ignoriert. Der Status eines untergeordneten Prozesses wird über eine 16-Bit-Ganzzahl an den übergeordneten Prozess zurückgegeben
Der Status wird vom
wait
Systemaufruf oder einem seiner Geschwister zurückgegeben. POSIX spezifiziert nicht die genaue Kodierung des Ausgangsstatus und der Signalnummer; es bietet nurGenau genommen gibt es keinen Exit- Code, wenn ein Prozess durch ein Signal beendet wird: Stattdessen gibt es einen Exit- Status .
In einem Shell-Skript wird der Beendigungsstatus eines Befehls über die spezielle Variable gemeldet
$?
. Diese Variable kodiert den Exit-Status mehrdeutig:$?
ist dies der Beendigungsstatus.$?
ist dies bei den meisten Systemen 128 plus der Signalnummer. POSIX$?
gibt in diesem Fall nur Mandate vor, die größer als 128 sind. ksh93 fügt 256 statt 128 hinzu. Ich habe noch nie eine Unix-Variante gesehen, die der Signalnummer eine andere Konstante hinzufügt.In einem Shell-Skript können Sie daher nicht abschließend sagen, ob ein Befehl durch ein Signal beendet oder mit einem Statuscode größer als 128 beendet wurde, außer mit ksh93. Es kommt sehr selten vor, dass Programme mit Statuscodes größer als 128 beendet werden, zum Teil, weil Programmierer dies aufgrund der
$?
Mehrdeutigkeit vermeiden .SIGINT ist bei den meisten Unix-Varianten Signal 2, also
$?
128 + 2 = 130 für einen Prozess, der von SIGINT beendet wurde. Sie sehen 129 für SIGHUP, 137 für SIGKILL usw.quelle
$?
nur für Bourne-ähnliche Muscheln gilt. Siehe auchyash
für ein anderes (aber immer noch POSIX-) Verhalten. Auch nach POSIX + XSI (Unix)kill -2 "$pid"
sendet a ein SIGINT an den Prozess, aber die tatsächliche Signalnummer ist möglicherweise nicht 2, also $? wird nicht unbedingt 128 + 2 (oder 256 + 2 oder 384 + 2) sein,kill -l "$?"
wird aber zurückkehrenINT
, weshalb ich aus Gründen der Portabilität raten würde, sich nicht auf die Nummern selbst zu beziehen.Das hängt von deiner Muschel ab. Auf der
bash(1)
Manpage, Abschnitt SHELL GRAMMAR , Unterabschnitt Simple Commands :Da
SIGINT
auf Ihrem System das Signal Nummer 2 ist, ist der Rückgabewert 130, wenn es unter Bash ausgeführt wird.quelle
signal(7)
Manpage wollen .Es scheint der richtige Ort zu sein, zu erwähnen, dass SVr4 1989 waitid () eingeführt hat, aber bisher scheint es kein wichtiges Programm zu verwenden. waitid () erlaubt es, die vollen 32 Bits vom exit () Code abzurufen.
Vor ungefähr 2 Monaten habe ich den Wait / Job Control-Teil der Bourne Shell neu geschrieben, um waitid () anstelle von waitpid () zu verwenden. Dies wurde gemacht, um die Einschränkung zu beseitigen, die den Exit-Code mit 0xFF maskiert.
Die waitid () - Schnittstelle ist viel sauberer als frühere wait () - Implementierungen, mit Ausnahme des Aufrufs cwait () von UNOS aus dem Jahr 1980.
Vielleicht interessiert es Sie, die Manpage zu lesen unter:
http://schillix.sourceforge.net/man/man1/bosh.1.html
und überprüfen Sie den Abschnitt "Parametersubstitution" auf Seite 8.
Die neuen Variablen .sh. * Wurden für die waitid () - Schnittstelle eingeführt. Diese Schnittstelle hat für die für $? Bekannten Zahlen keine mehrdeutigen Bedeutungen mehr. und machen die Anbindung viel einfacher.
Beachten Sie, dass Sie eine POSIX-kompatible waitid () benötigen, um diese Funktion nutzen zu können. Mac OS X und Linux bieten dies derzeit nicht an, aber die waitid () wird beim Aufruf von waitpid () emuliert Nicht-POSIX-Plattform erhalten Sie immer noch nur 8 Bit vom Exit-Code.
Kurz gesagt: .sh.status ist der numerische Beendigungscode, .sh.code ist der numerische Beendigungsgrund.
Zur besseren Portabilität gibt es: .sh.codename für die Textversion des Exit-Grunds, z. B. "DUMPED" und .sh.termsig, den Singal-Namen für das Signal, das den Prozess beendet hat.
Zur besseren Verwendung gibt es zwei nicht-exit-bezogene .sh.codename-Werte: "NOEXEC" und "NOTFOUND", die verwendet werden, wenn ein Programm überhaupt nicht gestartet werden kann.
FreeBSD hat den waitid () -Kerlnel-Fehler innerhalb von 20 Stunden nach meinem Bericht behoben. Linux hat noch nicht mit der Behebung begonnen. Ich hoffe, dass 26 Jahre nach der Einführung dieser Funktion, die jetzt in POSIX verfügbar ist, alle Betriebssysteme sie bald korrekt unterstützen werden.
quelle