GNU/Linux >> Tutoriels Linux >  >> Linux

Code de sortie par défaut lorsque le processus est terminé ?

Lorsqu'un processus est tué avec un signal gérable comme SIGINT ou SIGTERM mais 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 SIGINT entraîne probablement le code de sortie 130 , mais cela varierait-il selon l'implémentation du noyau ou du shell ?

$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130

Je ne sais pas comment je testerais les autres signaux…

$ ./myScript &
$ killall myScript
$ echo $?
0  # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0  # same problem

Réponse acceptée :

Les processus peuvent appeler le _exit() appel 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 gestionnaire sur SIGCHLD dans le parent pour récupérer ce code, mais pas sur Linux).

Le parent fera généralement un wait() ou waitpid() pour obtenir le statut de leur enfant sous la forme d'un entier (bien que waitid() avec une sémantique quelque peu différente peut également être utilisée).

Sous Linux et la plupart des Unix, si le processus s'est terminé normalement, les bits 8 à 15 de cet statut number contiendra le code de sortie tel qu'il est passé à exit() . Sinon, les 7 bits les moins significatifs (0 à 6) contiendront le numéro de signal et le bit 7 sera défini si un cœur a été vidé.

perl est $? par exemple contient ce nombre tel que défini par waitpid() :

$ 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

Les shells de type Bourne font é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 dessus, et c'est différent entre les coques.

Ce qui est commun à tous les shells, c'est que $? contient les 8 bits les plus bas du code de sortie (le nombre passé à exit() ) si le processus s'est terminé normalement.

Là où cela diffère, c'est lorsque le processus se termine par un signal. Dans tous les cas, et c'est requis par POSIX, le nombre sera supérieur à 128. POSIX ne précise 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 de $? contiendra le numéro de signal. Mais, où n est le numéro du signal,

  • dans ash, zsh, pdksh, bash, le shell Bourne, $? est 128 + n . Cela signifie que dans ces shells, 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 logique est que les shells, lorsqu'ils se quittent eux-mêmes, renvoient par défaut le statut de sortie de la dernière commande sortie. En vous assurant que $? n'est jamais supérieur à 255, ce qui permet d'avoir un statut de sortie cohérent :

    $ 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 , $? est 256 + n . Cela signifie qu'à partir d'une valeur de $? vous pouvez faire la différence entre un processus tué et non tué. Versions plus récentes de ksh , à la sortie, si $? était supérieur à 255, se tue 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 générera un core dump supplémentaire (écrasant potentiellement l'autre) si le processus a été tué par un signal de génération de core :

    $ 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.
    

    Là où vous pourriez même dire qu'il y a un bogue, c'est que ksh93 se tue même si $? provient d'un return 257 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 propose un compromis. Elle renvoie 256 + 128 + n . Cela signifie que nous pouvons également faire la différence entre un processus tué et un processus qui s'est terminé correctement. Et à la sortie, il rapportera 128 + n sans avoir à se suicider et les effets secondaires que cela peut avoir.

    $ 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
    

Pour obtenir le signal à partir 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 de numéros de signaux, uniquement des noms de signaux)

Connexe :sauvegardes au niveau octet ou au niveau fichier ?

Sur les fronts autres que Bourne :

  • csh /tcsh et fish identique au shell Bourne sauf que le statut est dans $status au lieu de $? (notez que zsh définit également $status pour la compatibilité avec csh (en plus de $? )).
  • rc :le statut de sortie est dans $status également, mais lorsqu'elle est tuée 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 encore une autre preuve de la bonne conception de ce shell.
  • es . le statut de sortie n'est pas une variable. Si vous vous en souciez, vous exécutez la commande en tant que :

    status = <={cmd}
    

    qui renverra un nombre ou sigterm ou sigsegv+core comme dans rc .

Peut-être que pour être complet, nous devrions mentionner zsh c'est $pipestatus et bash $PIPESTATUS des tableaux contenant l'état de sortie des composants du dernier pipeline.

Et aussi pour être complet, en ce qui concerne les fonctions shell et les fichiers sourcés, par défaut, les fonctions retournent avec le statut de sortie de la dernière commande exécutée, mais peuvent également définir explicitement un statut de retour avec le return intégré. 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éfinira $? à 210 , return -- -1 définira $? à 255.
  • zsh et pdksh (et dérivés autres que mksh ) autorise tout entier décimal signé de 32 bits (-2 à 2-1) (et tronque le nombre à 32 bits).
  • ash et yash autoriser tout entier positif de 0 à 2-1 et renvoyer une erreur pour tout nombre en dehors de cela.
  • ksh93 pour return 0 pour return 320 définir $? tel quel, mais pour toute autre chose, tronquer à 8 bits. Attention, comme déjà mentionné, le retour d'un nombre compris entre 256 et 320 pourrait causer ksh se suicider en sortant.
  • rc et es autoriser le renvoi de tout, même des listes.
Connexe :arduino - Gcode nécessite-t-il un code de réponse de l'interpréteur ?

Notez également que certains shells utilisent également des valeurs spéciales de $? /$status pour signaler certaines conditions d'erreur qui ne sont pas l'état de sortie d'un processus, comme 127 ou 126 pour commande introuvable ou non exécutable (ou erreur de syntaxe dans un fichier sourcé)…


Linux
  1. Les codes de sortie de la ligne de commande Bash démystifiés

  2. Linux - Quand ne devrais-je pas tuer -9 Un processus ?

  3. Pourquoi le mécanisme de création de processus par défaut est-il un fork ?

  4. Quel code d'erreur renvoie un processus renvoyant des erreurs de segmentation ?

  5. Invite Bash avec le dernier code de sortie

Que sont les codes de sortie Bash sous Linux

Quand assert() échoue, quel est le code de sortie du programme ?

exit() peut-il échouer à terminer le processus ?

Comment obtenir le code de sortie du processus généré dans le script shell attendu ?

Est-il possible d'appliquer un certain code de sortie lors de l'utilisation de kill pour arrêter un processus ?

pourquoi une boucle bash while ne se termine-t-elle pas lorsqu'elle est dirigée vers une sous-commande terminée?