Wenn ein Prozess mit einem handhabbaren Signal wie SIGINT
beendet wird oder SIGTERM
aber es verarbeitet das Signal nicht, wie lautet der Exit-Code des Prozesses?
Was ist mit nicht handhabbaren Signalen wie SIGKILL
?
Soweit ich das beurteilen kann, wird ein Prozess mit SIGINT
beendet führt wahrscheinlich zum 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
Akzeptierte Antwort:
Prozesse können _exit()
aufrufen Systemaufruf (unter Linux siehe auch exit_group()
). ) mit einem ganzzahligen Argument, um einen Beendigungscode an ihr übergeordnetes Element zu melden. Obwohl es sich um eine Ganzzahl handelt, stehen dem übergeordneten Element nur die 8 niederwertigsten Bits zur Verfügung (Ausnahme hiervon ist die Verwendung von waitid()
). oder Handler auf SIGCHLD im Elternteil, um diesen Code abzurufen, jedoch nicht unter Linux).
Der Elternteil führt normalerweise ein wait()
aus oder waitpid()
um den Status zu erhalten ihres Kindes als Ganzzahl (obwohl waitid()
mit etwas anderer Semantik können ebenfalls verwendet werden).
Unter Linux und den meisten Unices, wenn der Prozess normal beendet wurde, die Bits 8 bis 15 dieses Status Zahl enthält den Exit-Code, wie er an exit()
übergeben wird . Wenn nicht, enthalten die 7 niederwertigsten Bits (0 bis 6) die Signalnummer und Bit 7 wird gesetzt, wenn ein Kern ausgegeben wurde.
perl
ist $?
enthält beispielsweise diese Zahl, wie sie von waitpid()
gesetzt wird :
$ perl -e 'system q(kill $$); printf "%04xn", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04xn", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04xn", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status
Bourne-ähnliche Shells machen auch den Exit-Status des letzten Ausführungsbefehls in ihrem eigenen $?
Variable. Sie enthält jedoch nicht direkt die von waitpid()
zurückgegebene Zahl , aber eine Transformation darauf, und es ist zwischen den Shells unterschiedlich.
Was alle Shells gemeinsam haben, ist das $?
enthält die niedrigsten 8 Bits des Exit-Codes (die Zahl, die an exit()
übergeben wird ), wenn der Prozess normal beendet wurde.
Wo es sich unterscheidet, ist, wenn der Prozess durch ein Signal beendet wird. In allen Fällen, und das wird von POSIX verlangt, ist die Zahl größer als 128. POSIX gibt nicht an, was der Wert sein kann. In der Praxis sind jedoch in allen Bourne-ähnlichen Shells, die ich kenne, die niedrigsten 7 Bits von $?
enthält die Signalnummer. Aber wo n
ist die Signalnummer,
-
in ash, zsh, pdksh, bash, der Bourne-Shell,
$?
ist128 + n
. Das bedeutet, dass in diesen Shells ein$?
angezeigt wird von129
, wissen Sie nicht, ob es daran liegt, dass der Prozess mitexit(129)
beendet wurde oder ob es durch das Signal1
getötet wurde (HUP
auf den meisten Systemen). Der Grund dafür ist jedoch, dass Shells, wenn sie sich selbst beenden, standardmäßig den Beendigungsstatus des letzten beendeten Befehls zurückgeben. Indem Sie sicherstellen, dass$?
ist nie größer als 255, was einen konsistenten Exit-Status ermöglicht:$ bash -c 'sh -c "kill $$"; printf "%xn" "$?"' bash: line 1: 16720 Terminated sh -c "kill $$" 8f # 128 + 15 $ bash -c 'sh -c "kill $$"; exit'; printf '%xn' "$?" bash: line 1: 16726 Terminated sh -c "kill $$" 8f # here that 0x8f is from a exit(143) done by bash. Though it's # not from a killed process, that does tell us that probably # something was killed by a SIGTERM
-
ksh93
,$?
ist256 + n
. Das bedeutet, dass ab einem Wert von$?
Sie können zwischen einem beendeten und einem nicht beendeten Prozess unterscheiden. Neuere Versionen vonksh
, beim Beenden, wenn$?
größer als 255 war, beendet sich mit dem gleichen Signal selbst, um den gleichen Exit-Status an seinen Parent melden zu können. Das klingt zwar nach einer guten Idee, aber das bedeutet, dassksh
erzeugt einen zusätzlichen Core-Dump (der möglicherweise den anderen überschreibt), wenn der Prozess durch ein Core-Erzeugungssignal beendet wurde:$ ksh -c 'sh -c "kill $$"; printf "%xn" "$?"' ksh: 16828: Terminated 10f # 256 + 15 $ ksh -c 'sh -c "kill -ILL $$"; exit'; printf '%xn' "$?" ksh: 16816: Illegal instruction(coredump) Illegal instruction(coredump) 104 # 256 + 15, ksh did indeed kill itself so as to report the same # exit status as sh. Older versions of `ksh93` would have returned # 4 instead.
Wo man sogar sagen könnte, dass es einen Fehler gibt, ist dieser
ksh93
tötet sich selbst, selbst wenn$?
kommt von einemreturn 257
erfolgt durch eine Funktion:$ ksh -c 'f() { return "$1"; }; f 257; exit' zsh: hangup ksh -c 'f() { return "$1"; }; f 257; exit' # ksh kills itself with a SIGHUP so as to report a 257 exit status # to its parent
-
yash
.yash
bietet einen Kompromiss an. Es gibt256 + 128 + n
zurück . Das bedeutet, dass wir auch zwischen einem beendeten Prozess und einem ordnungsgemäß beendeten Prozess unterscheiden können. Und beim Beenden wird128 + n
gemeldet ohne sich selbst das Leben nehmen zu müssen und die Nebenwirkungen, die es haben kann.$ yash -c 'sh -c "kill $$"; printf "%xn" "$?"' 18f # 256 + 128 + 15 $ yash -c 'sh -c "kill $$"; exit'; printf '%xn' "$?" 8f # that's from a exit(143), yash was not killed
Um das Signal aus dem Wert von $?
zu erhalten , der portable Weg ist die Verwendung von kill -l
:
$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM
(aus Gründen der Portabilität sollten Sie niemals Signalnummern verwenden, sondern nur Signalnamen)
Verwandt:Sicherungen auf Byte- oder Dateiebene?An den Nicht-Bourne-Fronten:
csh
/tcsh
undfish
wie die Bourne-Shell, außer dass der Status in$status
steht statt$?
(Beachten Sie, dasszsh
setzt auch$status
für die Kompatibilität mitcsh
(zusätzlich zu$?
)).rc
:Der Exit-Status ist in$status
auch, aber wenn sie von einem Signal getötet wird, enthält diese Variable den Namen des Signals (wiesigterm
odersigill+core
wenn ein Kern generiert wurde) anstelle einer Zahl, was ein weiterer Beweis für das gute Design dieser Hülle ist.-
es
. der Exit-Status ist keine Variable. Wenn es Ihnen wichtig ist, führen Sie den Befehl wie folgt aus:status = <={cmd}
was eine Zahl oder
sigterm
zurückgibt odersigsegv+core
wie inrc
.
Vielleicht sollten wir der Vollständigkeit halber zsh
erwähnen 's $pipestatus
und bash
's $PIPESTATUS
Arrays, die den Exit-Status der Komponenten der letzten Pipeline enthalten.
Und auch der Vollständigkeit halber, wenn es um Shell-Funktionen und Quelldateien geht, kehren Funktionen standardmäßig mit dem Exit-Status der letzten Befehlsausführung zurück, können aber auch explizit mit return
einen Rückgabestatus setzen eingebaut. Und hier sehen wir einige Unterschiede:
bash
undmksh
(seit R41 eine offenbar absichtlich eingeführte Regression^Wchange) kürzt die Zahl (positiv oder negativ) auf 8 Bit. Also zum Beispielreturn 1234
setzt$?
bis210
,return -- -1
setzt$?
bis 255.zsh
undpdksh
(und andere Ableitungen alsmksh
) jede vorzeichenbehaftete 32-Bit-Dezimalzahl (-2 bis 2-1) zulassen (und die Zahl auf 32 Bit kürzen).ash
undyash
erlaubt jede positive ganze Zahl von 0 bis 2-1 und gibt einen Fehler für jede Zahl davon zurück.ksh93
fürreturn 0
umreturn 320
setze$?
unverändert, aber für alles andere auf 8 Bit abschneiden. Beachten Sie, wie bereits erwähnt, dass die Rückgabe einer Zahl zwischen 256 und 320 zuksh
führen kann um sich beim Beenden selbst zu töten.rc
undes
alles zurückgeben lassen, sogar Listen.
Beachten Sie auch, dass einige Shells auch spezielle Werte von $?
verwenden /$status
um einige Fehlerbedingungen zu melden, die nicht der Exit-Status eines Prozesses sind, wie 127
oder 126
für Befehl nicht gefunden oder nicht ausführbar (oder Syntaxfehler in einer Quelldatei)…