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

184

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?

Richard H
la source

Réponses:

182

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

kill -0 $pid

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

kill $pid

ou vous aurez une condition de course.

Si vous souhaitez ignorer la sortie de texte de killet 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
Christoffer Hammarström
la source
1
en regardant la page de manuel, kill -0 est: "le code de sortie indique si un signal peut être envoyé". Alors, est-ce que cela tue réellement un processus, ou vous dit-il simplement s'il peut être tué?
Richard H
24
killest quelque peu mal nommé en ce sens qu'il ne tue pas nécessairement le processus. Il envoie simplement un signal au processus. kill $PIDéquivaut à kill -15 $PID, qui envoie le signal 15, SIGTERM au processus, qui est une instruction pour terminer. Il n'y a pas de signal 0, c'est une valeur spéciale indiquant killsimplement de vérifier si un signal pourrait être envoyé au processus, ce qui est dans la plupart des cas plus ou moins équivalent à vérifier s'il existe. Voir linux.die.net/man/2/kill et linux.die.net/man/7/signal
Christoffer Hammarström
43
Cela pose le problème que si le processus n'appartient pas à l'utilisateur en cours d'exécution, vous ne disposez peut-être pas des autorisations pour appeler kill -0. Mieux vaut utiliser ps -p $ PID> / dev / null 2> & 1, qui vous permet de voir l'état du processus, même si vous ne disposez pas des autorisations pour envoyer un signal.
mckoss
6
@mckoss: Dans ce cas, il ne peut pas le tuer de toute façon.
Christoffer Hammarström
2
Donc, je suppose - pour utiliser kill -0, en fait, je dois faire ceci: kill -0 25667 ; echo $?- et ensuite si j'obtiens un 0retour, alors le processus avec ce PID peut être tué; et si le processus PID (disons) n'existe pas, le $?sera 1, indiquant un échec. Est-ce exact?
sdaau
264

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 différent de zéro même si le pid est en cours d'exécution et que vous n'avez pas l'autorisation de le tuer. Par exemple:

kill -0 1

et

kill -0 $non-running-pid

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

DISCUSSION

Les réponses concernant les conditions de mise à mort et de race sont exactement correctes si le corps du test est un "kill". Je suis venu chercher le général " comment testez-vous l'existence d'un PID dans bash ".

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

FDS
la source
1
ps -p renvoie toujours le statut 0 pour moi
IttayD
1
ps -p #### a bien fonctionné pour moi sous Ubuntu 14.04, +1 merci!
Ligemer
3
ps -p renvoie toujours le code d'état 0 dans os x car il imprime une liste vide de processus lorsqu'il ne correspond à aucun processus en cours d'exécution
Douglas Correa
Je peux confirmer que sur macOS Sierra, cela fonctionne. En outre, le -pn'est pas nécessaire, du moins dans ce cas. ps $PIDa exactement le même résultat.
user137369
La portabilité est une bonne raison d'éviter d'utiliser / proc, mais linux briser son ABI n'est pas un scénario qui m'inquiéterait particulièrement.
David Roundy
67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

ou

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

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

user2683246
la source
1
La deuxième méthode fonctionne également sur Mac, en plus (Mac OS X n'a ​​pas de / proc FS). Vous pouvez, cependant, éviter d'utiliser un sous-shell et l'utiliser à la fois sur Mac et Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Will
Malheureusement, les psoptions et les fonctionnalités ont tendance à varier entre les plates-formes, de sorte qu'elles ne sont toujours pas entièrement portables.
tripleee
1
si $PIDest vide, alors [ -e /proc/$PID ]retournera toujours true, puisque le /proc/répertoire existe toujours.
Magne
34

pscommande avec -p $PIDpeut faire ceci:

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

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 recherchent maintenant 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 recherche 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 méthode : cherchez simplement quelque chose dans le /proc/$PIDrépertoire. 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: quel est le problème avec kill -9 $PID || true?


ÉDITER:

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 hack, mais hautement non portable. 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 noyaux Linux. Veuillez utiliser "ps" comme décrit dans les autres réponses.

elcuco
la source
au moins la partie kill -9 semble fausse (ne tue pas les sous-processus)
nurettin
Pourquoi est-ce que j'obtiens [: missing `] 'lorsque j'utilise la première méthode?
tenmiles
1
/proc/$PID/exen'est pas un fichier ordinaire. Donc, [ -f /proc/$PID/exe ]retournera toujours un falserésultat. Essayez [ -h /proc/$PID/exe ].
Alexander Yancharuk
8

Il semble que tu veux

wait $PID

qui reviendra une fois $pidterminé.

Sinon, vous pouvez utiliser

ps -p $PID

pour vérifier si le processus est toujours en vie (c'est plus efficace que kill -0 $pidparce qu'il fonctionnera même si vous ne possédez pas le pid).

Gagan Gami
la source
1
attendre n'est pas aussi efficace que le processus devrait être enfant du shell actuel ou il donnera:pid 123 is not a child of this shell
Calumah
7

Je pense que c'est une mauvaise solution, qui ouvre aux conditions de course. Et si le processus meurt entre votre test et votre appel à tuer? Alors tuer échouera. Alors pourquoi ne pas simplement essayer le kill dans tous les cas, et vérifier sa valeur de retour pour savoir comment cela s'est passé?

se détendre
la source
+1 malheureusement, le code de sortie de kill (1) ne distingue pas les différentes situations d'erreur (on dirait qu'il incrémente la valeur de sortie de un pour chaque processus qu'il n'a pas réussi à signaler). si l'OP ne craint pas d'écrire son propre wrapper kill (2), il pourrait le faire quitter avec des valeurs différentes basées sur la valeur de ERRNO après un appel raté à kill (2).
juste quelqu'un
en ce moment je fais juste kill -9 sans contrôle - j'obtiens juste une erreur "le processus n'existe pas" s'il n'existe pas qui n'est pas très ordonné. Comment tester ce qui s'est passé?
Richard H
14
Ne soyez pas négligente kill -9. Cela tue instantanément le processus, ne lui donnant aucune chance de se nettoyer après lui-même. Utilisez plutôt killce qui équivaut à kill -15. Si cela ne fonctionne pas, vous devriez savoir pourquoi, et uniquement en dernier recours kill -9.
Christoffer Hammarström
0

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 elle ne vérifie pas comment ce pid est appelé. si le système est redémarré et que .pid existe mais est utilisé par une autre application, cela peut entraîner des «conséquences imprévues».

invalidmagic
la source
0

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.

inukaze
la source
1
pidofne renvoie pas de nombre négatif, car un PID négatif n'a aucun sens, et vous ne pouvez pas tuer init, donc votre conditionnel n'a aucun sens (et de plus, vous devrez échapper à >pour l'empêcher d'effectuer une redirection). Vous voulez vérifier un résultat vide, mais bien sûr, comme tout outil décent, pidofdéfinit un code de sortie pour vous dire si cela a fonctionné, donc la bonne solution est if Pid=$(pidof 'process_name'); then ...ou (si vous n'aurez pas besoin de la valeur Pidplus tard) simplementif pidof 'process_name'; then...
tripleee
@tripleee a raison, l' pidofexemple est plein de malentendus sur le fonctionnement de bash test. gnu.org/software/bash/manual/html_node/…
Bruno Bronosky
0

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

vérifions les nouveaux messages d'Amazon SQS toutes les heures uniquement 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 $?
Brian Sanchez
la source