web-dev-qa-db-fra.com

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

Dans un script bash, je souhaite effectuer les opérations suivantes (en pseudo-code):

if [ a process exists with $PID ]; then

    kill $PID 

fi

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

149
Richard H

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

kill -0 $pid

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

kill $pid

ou vous aurez une condition de concurrence.

Si vous voulez ignorer la sortie 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
153

Le meilleur moyen est:

if ps -p $PID > /dev/null
then
   echo "$PID is running"
   # Do something knowing the pid exists, i.e. 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 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 sur les conditions de mise à mort et de race sont exactes si le corps du test est une "mise à mort". Je suis venu à la recherche du général " comment testez-vous l'existence d'un PID dans bash ". 

La méthode/proc est intéressante, mais dans un sens, elle brise l’esprit de l’abstraction de la commande "ps", c’est-à-dire que vous n’avez pas besoin d’aller dans/proc car que se passera-t-il si Linus décide d’appeler autre chose le fichier "exe"?

220
FDS
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 permettant d'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.

55
user2683246

La commande ps avec -p $PID peut faire ceci:

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

Vous avez deux moyens:

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 maintenant rechercheront le PID 3358.

Première manière : Exécutez "ps aux" et grep pour le PID dans la deuxième colonne. Dans cet exemple, je cherche firefox, puis 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 manière : Il suffit de chercher quelque chose dans le répertoire /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: qu'est-ce qui ne va pas avec kill -9 $PID || true?


MODIFIER:

Après y avoir réfléchi pendant quelques mois ... (environ 24 ...), l’idée originale que j’ai donnée ici est un joli bidouillage, mais très peu transportable. Bien qu'il enseigne quelques détails d'implémentation de Linux, il ne fonctionnera pas sur Mac, Solaris ou * BSD. Cela pourrait même échouer sur les futurs noyaux Linux. Merci d'utiliser "ps" comme décrit dans d'autres réponses.

10
elcuco

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

7
unwind

On dirait que tu veux

wait $PID

qui retournera quand $pid finira.

Sinon, vous pouvez utiliser

ps -p $PID

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

3
Gagan Gami

Par exemple, sous 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.

0
inukaze

le code ci-dessous vérifie si mon processus est en cours d'exécution, si rien ne se passe.

vérifions les nouveaux messages d'Amazon SQS toutes les heures et uniquement si le processus n'est pas en cours d'exécution.

#!/bin/bash
PID=$(ps aux | grep '/usr/bin/python2.7 manage.py SES__boto3_sqs_read' | grep -v grep | awk '{print $2}')
if [[ -z $PID ]]; then
    /usr/bin/python2.7 /home/brian/djcode/proyectoONE/manage.py SES__boto3_sqs_read
else
    echo "do nothing, just smile =)"
fi
exit $?
0
Brian Sanchez

ici, je stocke le PID dans un fichier appelé .pid (qui est un peu comme/run/...) et n'exécute le script que 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 concurrence, car il ne vérifie pas comment ce pid est appelé. Si le système est redémarré et que le fichier .pid existe mais qu'il est utilisé par une application différente, cela peut entraîner des "conséquences imprévues".

0
invalidmagic