[Modifier: Cela ressemble à d'autres questions demandant comment tuer tous les processus générés - les réponses semblent toutes être d'utiliser pkill. Donc, le cœur de ma question peut être: existe-t-il un moyen de propager Ctrl-C / Z à tous les processus générés par un script?]
Lors de l'appel d'un SoX rec
avec la timeout
commande de coreutils (discuté ici ), il ne semble pas y avoir de moyen de le tuer avec une frappe une fois qu'il a été invoqué depuis un script Bash.
Exemples:
timeout 10 rec test.wav
... peut être tué avec Ctrl+ Cou Ctrl+ Zdepuis bash, mais pas quand il est appelé depuis l'intérieur d'un script.
timeout 10 ping nowhere
... peut être tué avec Ctrl+ Cou Ctrl+ Zdepuis bash, et avec Ctrl+ Zquand il est exécuté depuis l'intérieur d'un script.
Je peux trouver l'ID de processus et le tuer de cette façon, mais pourquoi ne puis-je pas utiliser une touche de pause standard? Et existe-t-il un moyen de structurer mon script pour que je puisse?
la source
bg
offg
. Quoi qu'il en soit, y a-t-il une différence entre vos 1er et 3e exemples?timeout
sur mon système, mais tuersleep
fonctionne, qu'il soit tapé directement sur la ligne de commande, sourcé, exécuté ou passé explicitement par l'interpréteurRéponses:
Les touches de signal telles que Ctrl+ Cenvoient un signal à tous les processus du groupe de processus de premier plan .
Dans le cas typique, un groupe de processus est un pipeline. Par exemple, dans
head <somefile | sort
, le processus en cours d'exécutionhead
et le processus en cours d'exécutionsort
sont dans le même groupe de processus, tout comme le shell, de sorte qu'ils reçoivent tous le signal. Lorsque vous exécutez un travail en arrière-plan (somecommand &
), ce travail se trouve dans son propre groupe de processus, donc appuyer sur Ctrl+ Cne l'affecte pas.Le
timeout
programme se place dans son propre groupe de processus. Du code source:Lorsqu'un délai d'expiration se produit,
timeout
passe par le simple moyen de tuer le groupe de processus dont il est membre. Puisqu'il s'est placé dans un groupe de processus séparé, son processus parent ne sera pas dans le groupe. L'utilisation d'un groupe de processus ici garantit que si l'application enfant se transforme en plusieurs processus, tous ses processus recevront le signal.Lorsque vous exécutez
timeout
directement sur la ligne de commande et appuyez sur Ctrl+ C, le SIGINT résultant est reçu à la fois partimeout
et par le processus enfant, mais pas par le shell interactif qui esttimeout
le processus parent. Quandtimeout
est appelé à partir d'un script, seul le shell exécutant le script reçoit le signal:timeout
ne l'obtient pas car il se trouve dans un groupe de processus différent.Vous pouvez définir un gestionnaire de signal dans un script shell avec la fonction
trap
intégrée. Malheureusement, ce n'est pas si simple. Considère ceci:Si vous appuyez sur Ctrl+ Caprès 2 secondes, cela attend toujours les 5 secondes complètes, puis imprimez le message «Interrompu». En effet, le shell s'abstient d'exécuter le code d'interruption lorsqu'un travail de premier plan est actif.
Pour y remédier, exécutez le travail en arrière-plan. Dans le gestionnaire de signaux, appelez
kill
pour relayer le signal autimeout
groupe de processus.la source
S'appuyant sur l'excellente réponse fournie par Gilles. La commande timeout a une option de premier plan, si elle est utilisée, un CTRL + C quittera la commande timeout.
la source
timeout
de GNU coreutils.Fondamentalement, Ctrl+ Cenvoie un
SIGINT
signal, tandis que Ctrl+ Z envoie unSIGTSTP
signal.SIGTSTP
arrête simplement le processus, unSIGCONT
le continuera.Cela fonctionne sur le processus de premier plan qui a été bifurqué sur la ligne de commande.
Si votre processus est un processus d'arrière-plan, vous devrez envoyer ce signal aux processus d'une manière différente.
kill
Fera cela. En théorie, un opérateur "-" sur ce kill devrait également signaler les processus enfants mais cela fonctionne rarement comme prévu.Pour en savoir plus: Unix-Signals
la source
Amélioration de la réponse de @Gilles en fournissant une approche "trouver et remplacer" pour les scripts existants:
INT
gestionnaire:timeout
commandes par unemy_timeout
fonction dans votre script.Exemple
Voici un exemple de script:
la source