Comment vérifier si un identifiant de processus (PID) existe

Dans un script bash, je veux faire ce qui suit (en pseudo-code):

if [ a process exists with $PID ]; then kill $PID fi 

Quelle est l’expression appropriée pour l’instruction conditionnelle?

Pour vérifier l’existence d’un processus, utilisez

 kill -0 $pid 

Mais tout comme @unwind a dit, si vous voulez le tuer de toute façon, juste

 kill $pid 

ou vous aurez une condition de course.

Si vous voulez ignorer la sortie de texte de kill et faire quelque chose en fonction du code de sortie, vous pouvez

 if ! kill $pid > /dev/null 2>&1; then echo "Could not send SIGTERM to process $pid" >&2 fi 

Le meilleur moyen est de:

 if ps -p $PID > /dev/null then echo "$PID is running" # Do something knowing the pid exists, ie the process with $PID is running fi 

Le problème avec:

 kill -0 $PID 

est le code de sortie sera non nul même si le pid est en cours d’exécution et que vous n’avez pas la permission de le tuer. Par exemple:

 kill -0 1 

et

 kill -0 $non-running-pid 

avoir un code de sortie indiscernable (non nul) pour un utilisateur normal, mais le processus init (PID 1) est certainement en cours d’exécution.

DISCUSSION

Les réponses concernant les conditions de mort et de race sont exactes si le corps du test est un “tuer”. Je suis venu chercher le général ” comment testez-vous l’existence d’un PID en bash “.

La méthode / proc est intéressante, mais brise en quelque sorte l’esprit de l’abstraction de la commande “ps”, c’est-à-dire que vous n’avez pas besoin de regarder dans / proc car si Linus décide d’appeler le fichier “exe” autrement?

 if [ -n "$PID" -a -e /proc/$PID ]; then echo "process exists" fi 

ou

 if [ -n "$(ps -p $PID -o pid=)" ] 

Dans la dernière forme, -o pid= est un format de sortie pour afficher uniquement la colonne d’ID de processus sans en-tête. Les guillemets sont nécessaires pour que l’opérateur de chaîne non vide -n donne un résultat valide.

ps commande ps avec -p $PID peut le faire:

 $ ps -p 3531 PID TTY TIME CMD 3531 ? 00:03:07 emacs 

Vous avez deux façons:

Commençons par rechercher une application spécifique dans mon ordinateur portable:

 [root@pinky:~]# ps fax | grep mozilla 3358 ? S 0:00 \_ /bin/sh /usr/lib/firefox-3.5/run-mozilla.sh /usr/lib/firefox-3.5/firefox 16198 pts/2 S+ 0:00 \_ grep mozilla 

Tous les exemples vont maintenant rechercher le PID 3358.

Première manière : Exécuter “ps aux” et grep pour le PID dans la deuxième colonne. Dans cet exemple, je recherche Firefox, puis pour son PID:

 [root@pinky:~]# ps aux | awk '{print $2 }' | grep 3358 3358 

Donc votre code sera:

 if [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then kill $PID fi 

Deuxième méthode : recherchez simplement quelque chose dans le /proc/$PID . J’utilise “exe” dans cet exemple, mais vous pouvez utiliser n’importe quoi d’autre.

 [root@pinky:~]# ls -l /proc/3358/exe lrwxrwxrwx. 1 elcuco elcuco 0 2010-06-15 12:33 /proc/3358/exe -> /bin/bash 

Donc votre code sera:

 if [ -f /proc/$PID/exe ]; then kill $PID fi 

BTW: ce qui ne va pas avec kill -9 $PID || true kill -9 $PID || true ?


MODIFIER:

Après y avoir réfléchi pendant quelques mois… (environ 24 heures), l’idée originale que j’ai donnée ici est un joli hack, mais très décevant. Bien qu’il enseigne quelques détails d’implémentation de Linux, il ne fonctionnera pas sur Mac, Solaris ou * BSD. Il pourrait même échouer sur les futurs kernelx Linux. S’il vous plaît – utilisez “ps” comme décrit dans d’autres réponses.

Je pense que c’est une mauvaise solution, qui ouvre pour les conditions de course. Que se passe-t-il si le processus meurt entre votre test et votre appel à tuer? Alors, tuer échouera. Alors pourquoi ne pas essayer le kill dans tous les cas, et vérifier sa valeur de retour pour savoir comment ça s’est passé?

On dirait que tu veux

 wait $PID 

qui retournera quand $pid termine.

Sinon, vous pouvez utiliser

 ps -p $PID 

pour vérifier si le processus est toujours actif (cela est plus efficace que kill -0 $pid car il fonctionnera même si vous ne possédez pas le pid).

Ici, je stocke le PID dans un fichier appelé .pid (qui est un peu comme / run / …) et exécute uniquement le script s’il n’est pas déjà exécuté.

 #!/bin/bash if [ -f .pid ]; then read pid < .pid echo $pid ps -p $pid > /dev/null r=$? if [ $r -eq 0 ]; then echo "$pid is currently running, not executing $0 twice, exiting now..." exit 1 fi fi echo $$ > .pid # do things here rm .pid 

note: il y a une condition de course car elle ne vérifie pas comment ce pid est appelé. Si le système est redémarré et que .pid existe mais qu’il est utilisé par une autre application, cela peut entraîner des «conséquences imprévues».

Par exemple, dans GNU / Linux, vous pouvez utiliser:

 Pid=$(pidof `process_name`) if [ $Pid > 0 ]; then do something else do something fi 

Ou quelque chose comme

 Pin=$(ps -A | grep name | awk 'print $4}') echo $PIN 

et cela vous montre le nom de l’application, juste le nom sans ID.