2010-12-15 87 views
4

J'ai un script bash qui effectue un traitement parallèle en boucle. Je ne veux pas que le processus parallèle pointe le CPU, donc j'utilise une commande de sommeil. Voici une version simplifiée.Bash: un sleep dans une boucle while obtient son propre pid

 
(while true;do sleep 99999;done)& 

J'execute la ligne ci-dessus à partir d'une invite de bash et obtenir quelque chose comme: [1] 12345

[1] est le nombre d'emplois et 12345 est l'ID de processus (pid) de la boucle while. Je fais kill 12345 et obtenir:

 
[1]+ Terminated    (while true; do 
    sleep 99999; 
done) 

Il ressemble a pris fin le script entier. Cependant, je fais un ps aux|grep sleep et je trouve que la commande sleep est toujours aussi forte mais avec son propre pid! Je peux tuer le sleep et tout semble bien. Cependant, si je devais d'abord tuer le sommeil, la boucle while commence un nouveau sleep pid. C'est une telle surprise pour moi puisque le sommeil n'est pas parallèle à la boucle while. La boucle elle-même est un seul chemin d'exécution.

J'ai donc deux questions:

  1. Pourquoi la commande sleep obtenir son propre ID de processus?
  2. Comment tuer facilement la boucle while et le sleep?

Répondre

5
  1. sommeil tire son propre PID parce qu'il est un processus en cours et à attendre. Essayez which sleep pour voir où c'est.
  2. Vous pouvez utiliser ps -uf pour voir l'arborescence de processus sur votre système. De là, vous pouvez déterminer ce que le PPID (parent PID) du shell (celui qui exécute la boucle) du sommeil est.
+1

Je vois. Je pensais que «dormir» était une commande intégrée à bash, pas un processus. Cela a plus de sens maintenant. – User1

+0

Si vous utilisez bash, 'type sleep' ou' type -a sleep' est préférable à 'which'. 'qui 'est un ordre externe; il ne peut pas détecter les alias, les fonctions ou les commandes intégrées. Comparez la sortie de 'which echo' et' type echo'. –

+0

@ User1: Des choses comme 'echo' sont des commandes intégrées parce que cela les rend plus efficaces (et dans certains cas, comme' cd', parce qu'elles ont une sémantique qui ne peut être obtenue en exécutant une commande externe). L'efficacité de 'sleep' est sans importance, il n'y a donc pas grand intérêt à en faire un built-in. –

1

Avez-vous essayé de faire kill %1, où 1 est le nombre que vous obtenez après le lancement de la commande en arrière-plan?

Je l'ai fait juste après le lancement (while true;do sleep 99999;done)& et il l'a terminé correctement.

1

"ps --ppid" sélectionne tous les processus avec le pid parent spécifié, par exemple:

$ (while true;do sleep 99999;done)& 
[1] 12345 

$ ppid=12345 ; kill -9 $ppid $(ps --ppid $ppid -o pid --no-heading) 
1

Vous pouvez arrêter le groupe de processus.

Pour trouver le groupe de processus de votre course de processus:

ps --no-headers -o "%r" -p 15864 

tuer ensuite le groupe de processus avec:

kill -- -[PGID] 

Vous pouvez le faire en une seule commande. Essayons-le:

$ (while true;do sleep 99999;done)& 
[1] 16151 

$ kill -- -$(ps --no-headers -o "%r" -p 16151) 
[1]+ Terminated    (while true; do 
    sleep 99999; 
done) 
0

Pour tuer la boucle while et le sleep en utilisant $! vous pouvez également utiliser un gestionnaire de signaux trap à l'intérieur du sous-shell.

(trap 'kill ${!}; exit' TERM; while true; do sleep 99999 & wait ${!}; done)& 
kill -TERM ${!} 
+0

Impossible de faire cela après relogin – okwap

1
  1. Parce que "sommeil" est un processus, pas une accumulation en fonction ou similaire

  2. Vous pouvez effectuer les opérations suivantes:

    (while true;do sleep 99999;done)& 
    whilepid=$! 
    kill -- -$whilepid 
    

Le code ci-dessus tue le groupe de processus, car le PID est spécifié comme un nombre négatif (par exemple -123 au lieu de 123). En outre, il utilise la variable $!, qui stocke le PID du dernier processus exécuté. Lorsque vous exécutez un processus en arrière-plan en mode interactif (c'est-à-dire en utilisant l'invite de ligne de commande), il crée un nouveau groupe de processus, ce qui vous arrive. De cette façon, il est relativement facile de tout "tuer", car il suffit de tuer tout le groupe de processus. Cependant, lorsque cela est fait dans un script, il ne crée aucun nouveau groupe, car tous les nouveaux processus appartiennent au script PID, même s'ils sont exécutés en arrière-plan (le contrôle des jobs est désactivé par défaut). Pour activer le contrôle des tâches dans un script, il suffit de mettre les éléments suivants au début du script:

#!/bin/bash 

set -m