Lorsqu'un processus est tué avec un signal gérable tel que SIGINT
ou SIGTERM
mais qu'il ne gère pas le signal, quel sera le code de sortie du processus?
Qu'en est-il des signaux impossibles à gérer, comme SIGKILL
?
D'après ce que je peux dire, tuer un processus avec des SIGINT
résultats probables dans un code de sortie 130
, mais est-ce que cela varie en fonction de la mise en œuvre du noyau ou du shell?
$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130
Je ne sais pas comment tester les autres signaux ...
$ ./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
la source
la 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.&
). Envoyez le signal depuis un autre processus shell (dans un autre terminal), que vous pourrez utiliser$?
après la fin de myScript.Réponses:
Les processus peuvent appeler l'appel
_exit()
système (sous Linux, voir aussiexit_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 dewaitid()
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()
ouwaitpid()
pour obtenir le statut de leur enfant sous forme d’entier (bien qu’unewaitid()
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 parwaitpid()
: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é parwaitpid()
, 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
$?
est128 + n
. Cela signifie que dans ces coquilles, si vous obtenez un$?
de129
, vous ne savez pas si c'est parce que le processus s'est terminé avecexit(129)
ou s'il a été tué par le signal1
(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:ksh93
,$?
est256 + 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 deksh
, 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 queksh
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: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'unreturn 257
fait fait par une fonction:yash
.yash
offre un compromis. Ça revient256 + 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 rapport128 + n
sans avoir à se suicider et les effets secondaires qu'il peut avoir.Pour obtenir le signal de la valeur de
$?
, la méthode portable consiste à utiliserkill -l
:(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
Etfish
même que le shell Bourne , sauf que l'état est au$status
lieu de$?
(notez quezsh
définit également$status
la compatibilité aveccsh
(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 (commesigterm
ousigill+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:qui retournera un nombre ou
sigterm
ousigsegv+core
comme dansrc
.Peut-être par souci d’exhaustivité, nous devrions mentionner
zsh
les tableaux de type '$pipestatus
etbash
'$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
etmksh
(depuis R41, une régression ^ Wchange apparemment introduite intentionnellement ) tronquera le nombre (positif ou négatif) à 8 bits. Ainsi, par exemplereturn 1234
, définissez$?
sur210
,return -- -1
définissez$?
sur 255.zsh
etpdksh
(et les dérivés autres quemksh
) autorisent tout entier décimal signé 32 bits signé (-2 31 à 2 31 -1) (et tronquent le nombre à 32 bits ).ash
etyash
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
pourreturn 0
aureturn 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 provoquerksh
sa mort à la sortie.rc
etes
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, comme127
ou126
pour une commande introuvable ou non exécutable (ou une erreur de syntaxe dans un fichier source) ...la source
an exit code to their parent
etto get the *status* of their child
. vous avez mis l'accent sur "statut". Estexit code
et*status*
le même? Cas oui, quelle est l'origine d'avoir deux noms? Cas pas pareil, pourriez-vous donner la définition / référence du statut?exit()
. L' état de sortie : le numéro obtenu,waitpid()
qui comprend le code de sortie, le numéro du signal et s'il y a eu ou non un noyau vidé. Et le nombre que certaines coques rendent disponible dans l'une de leurs variables spéciales ($?
,$status
) est une transformation de l' état de sortie de telle sorte qu'il contienne le code de sortie en cas de terminaison normale, mais transporte également des informations de signal si le processus a été tué (celui-ci est généralement appelé statut de sortie ). Tout cela est expliqué dans ma réponse.> 128
partie: "L'état de sortie d'une commande qui s'est terminée parce qu'elle a reçu un signal doit être signalé comme étant supérieur à 128." pubs.opengroup.org/onlinepubs/9699919799/utilities/…[email protected]
(à partir du 06/05/2015) ouXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Lorsqu'un processus se termine, il renvoie une valeur entière au système d'exploitation. Sur la plupart des variantes unix, cette valeur est prise modulo 256: tout sauf les bits de poids faible est ignoré. Le statut d’un processus enfant est renvoyé à son parent via un entier de 16 bits dans lequel
Le statut est renvoyé par l'
wait
appel système ou l'un de ses frères et soeurs. POSIX ne spécifie pas le codage exact de l'état de sortie et du numéro de signal; il ne fournit queÀ proprement parler, il n'y a pas de code de sortie lorsqu'un processus est tué par un signal: il existe plutôt un statut de sortie .
Dans un script shell, l' état de sortie d'une commande est signalé via la variable spéciale
$?
. Cette variable code l'état de sortie de manière ambiguë:$?
son statut de sortie est atteint.$?
est 128 plus le numéro du signal sur la plupart des systèmes. POSIX n'impose que des mandats$?
supérieurs à 128 dans ce cas; ksh93 ajoute 256 au lieu de 128. Je n'ai jamais vu de variante unix qui ne fasse rien d'autre que d'ajouter une constante au numéro du signal.Ainsi, dans un script shell, vous ne pouvez pas déterminer avec certitude si une commande a été supprimée par un signal ou si elle a été supprimée avec un code d'état supérieur à 128, sauf avec ksh93. Il est très rare que des programmes quittent avec des codes d'état supérieurs à 128, en partie parce que les programmeurs l'évitent en raison de l'
$?
ambiguïté.SIGINT est le signal 2 sur la plupart des variantes Unix, donc
$?
128 + 2 = 130 pour un processus qui a été tué par SIGINT. Vous verrez 129 pour SIGHUP, 137 pour SIGKILL, etc.la source
$?
concerne uniquement les coquilles de type Bourne. Voir aussiyash
pour un comportement différent (mais toujours POSIX). En outre, comme pour POSIX + XSI (Unix), akill -2 "$pid"
enverra un SIGINT au processus, mais le numéro de signal réel peut ne pas être 2, alors $? ne sera pas nécessairement 128 + 2 (ou 256 + 2 ou 384 + 2), maiskill -l "$?"
reviendraINT
, c'est pourquoi je conseillerais pour la portabilité de ne pas se référer aux numéros eux-mêmes.Cela dépend de votre coquille. De la
bash(1)
page de manuel, section SHELL GRAMMAR, sous- section Commandes simples :Comme
SIGINT
le signal 2 est sur votre système, la valeur de retour est 130 lorsqu’il est exécuté sous Bash.la source
signal(7)
page de manuel également.Il semble être le bon endroit pour mentionner que SVr4 a introduit waitid () en 1989, mais aucun programme important ne semble l’utiliser jusqu’à présent. waitid () permet de récupérer les 32 bits complets du code exit ().
Il y a environ 2 mois, j'ai réécrit la partie wait / job control du Bourne Shell afin qu'elle utilise waitid () au lieu de waitpid (). Cela a été fait afin de supprimer la limitation qui masque le code de sortie avec 0xFF.
L’interface waitid () est bien plus propre que les implémentations précédentes de wait (), à l’exception de l’appel cwait () de UNOS à partir de 1980.
Vous pouvez être intéressé par la page de manuel à:
http://schillix.sourceforge.net/man/man1/bosh.1.html
et vérifiez la section "Substitution de paramètres" à la page 8.
Les nouvelles variables .sh. * Ont été introduites pour l'interface waitid (). Cette interface n'a plus de signification ambiguë pour les nombres connus pour $? et rendre l'interfaçage beaucoup plus facile.
Notez que vous devez disposer d'un waitid () compatible POSIX pour pouvoir utiliser cette fonctionnalité. Par conséquent, Mac OS X et Linux ne l'offrent pas actuellement, mais le waitid () est émulé sur l'appel waitpid (), donc une plate-forme non-POSIX, vous ne recevrez toujours que 8 bits du code de sortie.
En bref: .sh.status est le code de sortie numérique, .sh.code est la raison de la sortie numérique.
Pour une meilleure portabilité, il existe: .sh.codename pour la version textuelle du motif de sortie, par exemple "DUMPED" et .sh.termsig, nom unique du signal qui a mis fin au processus.
Pour une meilleure utilisation, il existe deux valeurs .sh.codename non liées à l'exit: "NOEXEC" et "NOTFOUND" qui sont utilisées lorsqu'un programme ne peut pas être lancé du tout.
FreeBSD a corrigé leur bug kerlnel waitid () dans les 20 heures suivant mon rapport, Linux n’ayant pas encore démarré avec leur correctif. J'espère que 26 ans après l'introduction de cette fonctionnalité présente dans POSIX, tous les systèmes d'exploitation le supporteront bientôt.
la source