2009-12-15 2 views
277

Je démarre un processus d'arrière-plan à partir de mon script shell, et je voudrais tuer ce processus lorsque mon script se termine.Comment obtenir un PID du processus d'arrière-plan?

Comment obtenir le PID de ce processus à partir de mon script shell? Pour autant que je peux voir la variable $! contient le PID du script en cours, pas le processus d'arrière-plan.

+5

$! est correct. Êtes-vous sûr de commencer le script dans le BG? échantillon s'il vous plaît. – pixelbeat

+4

Oui $! est correct. J'avais tort. –

+8

$$ contient le PID de script actuel. – HUB

Répondre

398

Vous devez enregistrer le PID du backgroun processus d au moment où vous le démarrer:

foo & 
FOO_PID=$! 
# do other stuff 
kill $FOO_PID 

Vous ne pouvez pas utiliser le contrôle de l'emploi, puisque c'est une fonction interactive et liée à un terminal de contrôle. Un script n'aura pas nécessairement de terminal attaché, donc le contrôle du travail ne sera pas nécessairement disponible.

+11

Depuis $! retourne le pid du dernier processus d'arrière-plan. Est-il possible que quelque chose commence entre 'foo' et' $! ', Et nous obtenons que quelque chose est pid au lieu de' foo'? – WiSaGaN

+29

@WiSaGaN: Non. Il n'y a rien entre ces lignes. Toute autre activité sur le système n'affectera pas cela. $! s'étendra au PID du dernier processus d'arrière-plan _dans ce shell_. – camh

+6

... qui vous ennuie si 'foo' se trouve être plusieurs commandes canalisées (par exemple' queue -f somefile.txt | grep sometext'). Dans ce cas, vous obtiendrez le PID de la commande grep de '$!' Plutôt que la commande tail si c'est ce que vous cherchiez. Vous devrez utiliser 'jobs' ou' ps' ou les likes dans cette instance. –

96

Vous pouvez utiliser la commande jobs -l pour se rendre à un jobL particulier

^Z 
[1]+ Stopped     guard 

my_mac:workspace r$ jobs -l 
[1]+ 46841 Suspended: 18   guard 

Dans ce cas, 46841 est le PID.

De help jobs:

-l Signaler l'ID du groupe de processus et répertoire de travail des emplois.

jobs -p est une autre option qui affiche uniquement les PID.

+0

Pour l'utiliser dans un script shell, vous devez traiter la sortie. – Phil

+6

@Phil Pour lister les pids uniquement: jobs -p. Pour lister le pid d'un certain travail: jobs -p% 3. Pas besoin de traiter la sortie. –

+0

@Erik avec différentes commandes/arguments vous changez le contexte de mon commentaire. Sans l'argument supplémentaire suggéré, la sortie nécessite un traitement. Suggérer une amélioration à la réponse! – Phil

33
  • $$ est le pid actuel scénario
  • $! est le pid du dernier processus d'arrière-plan

Voici une transcription de l'échantillon d'une session bash (%1 fait référence au nombre ordinal de processus d'arrière-plan vu de jobs):

$ echo $$ 
3748 

$ sleep 100 & 
[1] 192 

$ echo $! 
192 

$ kill %1 

[1]+ Terminated    sleep 100 
+0

echo '% 1' ne retourne pas le processus d'arrière-plan sur mon Ubuntu alors que' echo $! 'Le fait – Timo

2

Vous pourriez également être en mesure d'utiliser pstree:

pstree -p user 

Cela donne généralement une représentation textuelle de tous les processus pour le « utilisateur » et l'option -p donne le processus id. Pour autant que je sache, cela ne dépend pas du fait que les processus soient la propriété du shell actuel. Il montre également des fourchettes.

+1

Pour utiliser ceci dans un script shell, vous devez traiter fortement le résultat. – Phil

3

c'est ce que j'ai fait. Vérifiez-le, espérons que cela peut aider.

#!/bin/bash 
# 
# So something to show. 
echo "UNO" > UNO.txt 
echo "DOS" > DOS.txt 
# 
# Initialize Pid List 
dPidLst="" 
# 
# Generate background processes 
tail -f UNO.txt& 
dPidLst="$dPidLst $!" 
tail -f DOS.txt& 
dPidLst="$dPidLst $!" 
# 
# Report process IDs 
echo PID=$$ 
echo dPidLst=$dPidLst 
# 
# Show process on current shell 
ps -f 
# 
# Start killing background processes from list 
for dPid in $dPidLst 
do 
     echo killing $dPid. Process is still there. 
     ps | grep $dPid 
     kill $dPid 
     ps | grep $dPid 
     echo Just ran "'"ps"'" command, $dPid must not show again. 
done 

Ensuite, il suffit d'exécuter comme: ./bgkill.sh avec des autorisations appropriées bien sûr

[email protected] [P]:~# ./bgkill.sh 
PID=23757 
dPidLst= 23758 23759 
UNO 
DOS 
UID  PID PPID C STIME TTY   TIME CMD 
root  3937 3935 0 11:07 pts/5 00:00:00 -bash 
root  23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh 
root  23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt 
root  23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt 
root  23760 23757 0 11:55 pts/5 00:00:00 ps -f 
killing 23758. Process is still there. 
23758 pts/5 00:00:00 tail 
./bgkill.sh: line 24: 23758 Terminated    tail -f UNO.txt 
Just ran 'ps' command, 23758 must not show again. 
killing 23759. Process is still there. 
23759 pts/5 00:00:00 tail 
./bgkill.sh: line 24: 23759 Terminated    tail -f DOS.txt 
Just ran 'ps' command, 23759 must not show again. 
[email protected] [P]:~# ps -f 
UID  PID PPID C STIME TTY   TIME CMD 
root  3937 3935 0 11:07 pts/5 00:00:00 -bash 
root  24200 3937 0 11:56 pts/5 00:00:00 ps -f 
1

pgrep pouvez-vous obtenir tous les PIDs enfants d'un processus parent. Comme mentionné précédemment $$ est le PID de scripts en cours.Donc, si vous voulez un script qui nettoie après lui-même, cela devrait faire l'affaire:

trap 'kill $(pgrep -P $$ | tr "\n" " ")' SIGINT SIGTERM EXIT 
+0

Ne serait-ce pas tuer le sort? – Phil

+0

Oui, la question n'a jamais été mentionnée en gardant _some_ les enfants de fond en vie à la sortie. –

+0

'trap 'pkill -P $$' SIGINGM SIGERM EXIT' semble plus simple, mais je ne l'ai pas testé. – petre

19

Une encore plus simple moyen de tuer tous les processus enfant d'un script bash:

pkill -P $$ 

Le -P drapeau fonctionne de la même manière avec pkill et pgrep - il obtient des processus fils, seulement avec pkill les processus fils sont tués et avec pgrep les PID enfants sont imprimés sur stdout.

+0

Bonne réponse! Merci :) –

+0

Vous êtes les bienvenus :) –

+0

Très pratique! C'est le meilleur moyen de ne pas laisser les processus ouverts en arrière-plan. – lepe

Questions connexes