Si j'utilise trap
comme décrit par exemple sur http://linuxcommand.org/wss0160.php#trap pour attraper ctrl-c (ou similaire) et nettoyer avant de quitter, je change le code de sortie retourné.
Maintenant, cela ne fera probablement pas de différence dans le monde réel (par exemple parce que les codes de sortie ne sont pas portables et en plus de cela pas toujours sans ambiguïté comme discuté dans Code de sortie par défaut lorsque le processus est terminé? ) Mais je me demande toujours s'il y a vraiment aucun moyen d'empêcher cela et de retourner le code d'erreur par défaut pour les scripts interrompus à la place?
Exemple (en bash, mais ma question ne doit pas être considérée comme spécifique à bash):
#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _
Production:
$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT
EXIT
$ echo $?
1
(Modifié pour le supprimer afin de le rendre plus conforme à POSIX.)
(Modifié à nouveau pour en faire un script bash à la place, ma question n'est pas spécifique au shell.)
Édité pour utiliser le "INT" portable pour le piège en faveur du "SIGINT" non portable.
Modifié pour supprimer les accolades inutiles et ajouter une solution potentielle.
Mettre à jour:
Je l'ai résolu maintenant en quittant simplement avec certains codes d'erreur codés en dur et en piégeant EXIT. Cela peut être problématique sur certains systèmes car le code d'erreur peut différer ou le piège EXIT n'est pas possible, mais dans mon cas, c'est assez bien.
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
read
de lire à partir du coprocessus actuel ettrap cmd SIGINT
ne fonctionnera pas comme le standard dit que vous devez utilisertrap cmd INT
.read -p
lecture des entrées du coprocessus actuel.Réponses:
Tout ce que vous devez faire est de changer le gestionnaire EXIT dans votre gestionnaire de nettoyage. Voici un exemple:
la source
trap cleanup INT
au lieu detrap cleanup EXIT
?En fait, l'interruption de l'interne de bash
read
semble être un peu différente de l'interruption d'une commande exécutée par bash. Normalement, lorsque vous entreztrap
,$?
est défini et vous pouvez le conserver et quitter avec la même valeur:Si votre script est interrompu lors de l'exécution d'une commande comme
sleep
ou même d'une commande intégréewait
, vous verrezet le code de sortie est 130. Cependant, pour
read -p
, il semble$?
être 0 (de toute façon sur ma version de bash 4.3.42).Le traitement des signaux pendant
read
pourrait être en cours, selon le fichier des changements dans ma version ... (/ usr / share / doc / bash / CHANGES)la source
read
, comme indiqué dans le fichier CHANGES (ajouté à ma réponse). Donc, ce pourrait être un travail en cours.128 + signo
comme code de sortie pour les signaux, ksh93 utilise256 + signo
. POSIX dit: quelque chose au-dessus de 128 ....Tout code de sortie de signal habituel sera disponible lors
$?
de l'entrée dans le gestionnaire de déroutement:S'il existe une interruption EXIT distincte, vous pouvez utiliser la même méthodologie: conserver immédiatement le statut de sortie transmis par le gestionnaire de signaux (s'il y en a un), puis renvoyer le statut de sortie enregistré.
la source
local
n'est pas POSIX cependant.{ba,z}sh
. AFAIK, c'est le mieux qui puisse être fait, peu importe.$?
est 1 quel que soit le signal reçu).Il suffit de renvoyer un code d'erreur ne suffit pas pour simuler une sortie par SIGINT. Je suis surpris que personne n'ait mentionné cela jusqu'à présent. Pour en savoir plus: https://www.cons.org/cracauer/sigint.html
La bonne façon est:
Cela fonctionne avec Bash, Dash et zsh. Pour plus de portabilité, vous devez utiliser des spécifications de signal numérique (d'un autre côté, zsh attend un paramètre de chaîne pour la
kill
commande ...)Notez également le traitement spécial du
EXIT
signal. Cela est dû au fait que certains shells (à savoir Bash) exécutent également des interruptionsEXIT
pour tout signal (après des interruptions éventuellement définies sur ce signal). La réinitialisation duEXIT
piège empêche cela.Exécution de code uniquement à la sortie "normale"
La vérification
[ $sig = EXIT ]
permet d'exécuter du code uniquement à la sortie normale (non signalée). Cependant, tous les signaux doivent avoir des pièges qui réinitialisent enfin le piègeEXIT
;normal_exit_only_cleanup
sera également appelé pour les signaux qui ne le font pas. Il sera également exécuté par une sortie viaset -e
. Cela peut être résolu en interceptantERR
(qui n'est pas pris en charge par Dash) et en ajoutant une vérification[ $sig = ERR ]
avant lekill
.Version simplifiée Bash uniquement
D'un autre côté, ce comportement signifie que dans Bash, vous pouvez simplement faire
pour simplement exécuter du code de nettoyage et conserver l'état de sortie.
édité
Élaborer le comportement de Bash de "EXIT piège tout"
Supprimer le signal KILL, qui ne peut pas être piégé
Supprimer les préfixes SIG des noms de signaux
N'essayez pas de
kill -s EXIT
Prendre
set -e
en compte / ERRla source
SIGINT
est le moyen de l'arrêter et il peut décider de quitter avec 0 s'il a réussi à se terminer sans erreur ou un autre code d'erreur s'il ne s'est pas arrêté proprement. Exemple:top
. Exécuteztop; echo $?
, puis appuyez sur Ctrl-C. Le statut affiché à l'écran sera 0.