Les processus peuvent appeler l'appel _exit()
système (sous Linux, voir aussi exit_group()
) avec un argument entier pour signaler un code de sortie à leur parent. Bien qu'il s'agisse d'un entier, seuls les 8 bits les moins significatifs sont disponibles pour le parent (à l'exception de l' utilisation de waitid()
ou du gestionnaire sur SIGCHLD dans le parent pour récupérer ce code , mais pas sous Linux).
Les parents font généralement un wait()
ou waitpid()
pour obtenir le statut de leur enfant sous forme d’entier (bien qu’une waitid()
sémantique quelque peu différente puisse également être utilisée).
Sous Linux et la plupart des Unices, si le processus s'est terminé normalement, les bits 8 à 15 de ce numéro d' état contiendront le code de sortie tel que transmis exit()
. Si ce n'est pas le cas, les 7 bits les moins significatifs (0 à 6) contiendront le numéro du signal et le bit 7 sera activé si un cœur a été vidé.
perl
's $?
par exemple contient ce nombre tel que défini par waitpid()
:
$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status
Les shells de type Bourne définissent également le statut de sortie de la dernière commande d'exécution dans leur propre $?
variable. Cependant, il ne contient pas directement le nombre retourné par waitpid()
, mais une transformation, et il est différent entre les shells.
Ce qui est commun entre tous les shells est qu’il $?
contient les 8 bits les plus bas du code de sortie (le nombre transmis à exit()
) si le processus s’est terminé normalement.
La différence est lorsque le processus est terminé par un signal. Dans tous les cas, et cela est requis par POSIX, le nombre sera supérieur à 128. POSIX ne spécifie pas quelle peut être la valeur. En pratique cependant, dans tous les shells de type Bourne que je connais, les 7 bits les plus bas $?
contiendront le numéro du signal. Mais, où n
est le numéro de signal,
en ash, zsh, pdksh, bash, le shell Bourne $?
est 128 + n
. Cela signifie que dans ces coquilles, si vous obtenez un $?
de 129
, vous ne savez pas si c'est parce que le processus s'est terminé avec exit(129)
ou s'il a été tué par le signal 1
( HUP
sur la plupart des systèmes). Mais la raison en est que les shells, lorsqu'ils sortent d'eux-mêmes, retournent par défaut le statut de sortie de la dernière commande sortie. En s'assurant que rien $?
n'est jamais supérieur à 255, cela permet d'avoir un statut de sortie cohérent:
$ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
bash: line 1: 16720 Terminated sh -c "kill \$\$"
8f # 128 + 15
$ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
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
, $?
est 256 + n
. Cela signifie que $?
vous pouvez faire la différence entre un processus tué et non tué à partir d’une valeur de celui -ci. Les versions plus récentes de ksh
, si exit $?
était supérieur à 255, se tuent avec le même signal afin de pouvoir signaler le même état de sortie à son parent. Bien que cela semble être une bonne idée, cela signifie que ksh
cela générera un core dump supplémentaire (potentiellement écrasant l’autre) si le processus était tué par un signal générateur de core:
$ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
ksh: 16828: Terminated
10f # 256 + 15
$ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
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.
Là où vous pourriez même dire qu'il y a un bogue, c'est qu'il se ksh93
tue, même s'il $?
vient d'un return 257
fait fait par une fonction:
$ 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
offre un compromis. Ça revient 256 + 128 + n
. Cela signifie que nous pouvons également faire la différence entre un processus tué et un qui s'est terminé correctement. Et lors de la sortie, il fera rapport 128 + n
sans avoir à se suicider et les effets secondaires qu'il peut avoir.
$ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
18f # 256 + 128 + 15
$ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
8f # that's from a exit(143), yash was not killed
Pour obtenir le signal de la valeur de $?
, la méthode portable consiste à utiliser kill -l
:
$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM
(pour la portabilité, vous ne devez jamais utiliser les numéros de signal, seulement les noms de signal)
Sur les fronts non-Bourne:
csh
/ tcsh
Et fish
même que le shell Bourne , sauf que l'état est au $status
lieu de $?
(notez que zsh
définit également $status
la compatibilité avec csh
(en plus $?
)).
rc
: l'état de sortie est $status
également présent, mais lorsqu'il est tué par un signal, cette variable contient le nom du signal (comme sigterm
ou sigill+core
si un noyau a été généré) au lieu d'un nombre, ce qui est une autre preuve du bon design de ce shell .
es
. le statut de sortie n'est pas une variable. Si vous en tenez compte, vous exécutez la commande en tant que:
status = <={cmd}
qui retournera un nombre ou sigterm
ou sigsegv+core
comme dans rc
.
Peut-être par souci d’exhaustivité, nous devrions mentionner zsh
les tableaux de type ' $pipestatus
et bash
' $PIPESTATUS
qui contiennent l’état de sortie des composants du dernier pipeline.
Et aussi par souci d'exhaustivité, en ce qui concerne les fonctions shell et les fichiers sources, les fonctions retournent par défaut avec le statut de sortie de la dernière commande exécutée, mais peuvent également définir explicitement un statut de retour avec la commande return
intégrée. Et nous voyons quelques différences ici:
bash
et mksh
(depuis R41, une régression ^ Wchange apparemment introduite intentionnellement ) tronquera le nombre (positif ou négatif) à 8 bits. Ainsi, par exemple return 1234
, définissez $?
sur 210
, return -- -1
définissez $?
sur 255.
zsh
et pdksh
(et les dérivés autres que mksh
) autorisent tout entier décimal signé 32 bits signé (-2 31 à 2 31 -1) (et tronquent le nombre à 32 bits ).
ash
et yash
autorise tout nombre entier positif compris entre 0 et 2 31 -1 et renvoie une erreur pour tout nombre en dehors de celui-ci.
ksh93
pour return 0
au return 320
jeu $?
tel qu'il est, mais pour tout le reste, troncature à 8 bits. Attention, comme déjà mentionné, le fait de renvoyer un nombre compris entre 256 et 320 pourrait provoquer ksh
sa mort à la sortie.
rc
et es
permettent de retourner n'importe quoi, même des listes.
Notez également que certains shells utilisent également des valeurs spéciales $?
/ $status
pour signaler certaines conditions d'erreur qui ne sont pas le statut de sortie d'un processus, comme 127
ou 126
pour une commande introuvable ou non exécutable (ou une erreur de syntaxe dans un fichier source) ...
killall myScript
travaux, d’où le retour du killall (et non du script!) à 0. Vous pouvez placer unkill -x $$
[x représentant le numéro du signal et $$ généralement étendu par le shell au PID de ce script (fonctionne dans sh, bash, ...)] à l' intérieur du script, puis testez son noyau de sortie.