So überprüfen Sie, ob eine Prozess-ID (PID) vorhanden ist

184

In einem Bash-Skript möchte ich Folgendes tun (im Pseudocode):

if [ a process exists with $PID ]; then

    kill $PID 

fi

Was ist der passende Ausdruck für die bedingte Anweisung?

Richard H.
quelle

Antworten:

182

Verwenden Sie, um die Existenz eines Prozesses zu überprüfen

kill -0 $pid

Aber genau wie @unwind sagte, wenn du es trotzdem töten willst, einfach

kill $pid

oder Sie haben eine Rennbedingung.

Wenn Sie die Textausgabe von ignorieren killund etwas basierend auf dem Exit-Code tun möchten , können Sie dies tun

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
Christoffer Hammarström
quelle
1
Auf der Manpage lautet kill -0: "Exit-Code zeigt an, ob ein Signal gesendet werden kann". Tötet dies tatsächlich einen Prozess oder sagt es Ihnen nur, ob er getötet werden kann?
Richard H
23
killist etwas falsch benannt, da es den Prozess nicht unbedingt beendet. Es sendet dem Prozess nur ein Signal. kill $PIDist äquivalent zu kill -15 $PID, was das Signal 15 SIGTERM an den Prozess sendet, der eine Anweisung zum Beenden ist. Es gibt kein Signal 0, das ist ein spezieller Wert, killder nur prüft, ob ein Signal an den Prozess gesendet werden kann, was für die meisten Zwecke mehr oder weniger der Überprüfung entspricht, ob es existiert. Siehe linux.die.net/man/2/kill und linux.die.net/man/7/signal
Christoffer Hammarström
43
Dies hat das Problem, dass Sie möglicherweise keine Berechtigung zum Aufrufen von kill -0 haben, wenn der Prozess nicht dem laufenden Benutzer gehört. Verwenden Sie besser ps -p $ PID> / dev / null 2> & 1, damit Sie den Prozessstatus anzeigen können, auch wenn Sie keine Berechtigung zum Senden eines Signals haben.
McKoss
6
@ McKoss: In diesem Fall kann er es sowieso nicht töten.
Christoffer Hammarström
2
Also, ich denke - um es zu verwenden kill -0, muss ich tatsächlich Folgendes tun: kill -0 25667 ; echo $?- und wenn ich dann eine 0Rückgabe bekomme , kann der Prozess mit dieser PID abgebrochen werden; und wenn die Prozess-PID (sagen wir) nicht existiert, $?ist dies ein 1Hinweis auf einen Fehler. Ist das korrekt?
Sdaau
264

Der beste Weg ist:

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

Das Problem mit:

kill -0 $PID

ist, dass der Exit-Code ungleich Null ist, auch wenn die PID ausgeführt wird und Sie keine Berechtigung haben, sie zu beenden. Beispielsweise:

kill -0 1

und

kill -0 $non-running-pid

Sie haben einen nicht unterscheidbaren Exit-Code (ungleich Null) für einen normalen Benutzer, aber der Init-Prozess (PID 1) wird mit Sicherheit ausgeführt.

DISKUSSION

Die Antworten zu Kill- und Race-Bedingungen sind genau richtig, wenn der Testkörper ein "Kill" ist. Ich suchte nach dem allgemeinen " Wie testest du eine PID-Existenz in Bash?" ".

Die / proc-Methode ist interessant, bricht aber in gewissem Sinne den Geist der "ps" -Befehlsabstraktion, dh Sie müssen nicht in / proc suchen, denn was ist, wenn Linus beschließt, die "exe" -Datei etwas anderes aufzurufen?

FDS
quelle
1
ps -p gibt für mich immer den Status 0 zurück
IttayD
1
ps -p #### hat unter Ubuntu 14.04 gut funktioniert, +1 danke!
Ligemer
3
ps -p gibt immer den Statuscode 0 in os x zurück, weil es eine leere Liste von Prozessen druckt, wenn es keinem laufenden Prozess entspricht
Douglas Correa
Ich kann bestätigen, dass dies unter macOS Sierra funktioniert. Auch das -pist zumindest in diesem Fall unnötig. ps $PIDhat genau das gleiche Ergebnis.
user137369
Portabilität ist ein guter Grund, die Verwendung von / proc zu vermeiden, aber Linux, das seinen ABI bricht, ist kein Szenario, über das ich mir besonders Sorgen machen würde.
David Roundy
66
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

oder

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

In der letzteren Form -o pid=ist ein Ausgabeformat, um nur die Prozess-ID-Spalte ohne Kopfzeile anzuzeigen. Die Anführungszeichen sind erforderlich, damit ein nicht leerer Zeichenfolgenoperator -nein gültiges Ergebnis liefert.

user2683246
quelle
1
Die zweite Methode funktioniert auch auf dem Mac als zusätzliches Plus (Mac OS X hat kein / proc FS). Sie können jedoch die Verwendung einer Subshell vermeiden und diese sowohl auf Mac als auch auf Linux verwenden:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Will
Leider psvariieren die Optionen und Funktionen in der Regel zwischen den Plattformen, sodass sie immer noch nicht vollständig portierbar sind.
Tripleee
1
Wenn $PIDleer ist, [ -e /proc/$PID ]wird immer noch true zurückgegeben, da das /proc/Verzeichnis noch vorhanden ist.
Magne
34

psBefehl mit -p $PIDkann dies tun:

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

Sie haben zwei Möglichkeiten:

Beginnen wir mit der Suche nach einer bestimmten Anwendung in meinem Laptop:

[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

Alle Beispiele suchen jetzt nach PID 3358.

Erster Weg : Führen Sie "ps aux" aus und suchen Sie in der zweiten Spalte nach der PID. In diesem Beispiel suche ich nach Firefox und dann nach PID:

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

Ihr Code lautet also:

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

Zweiter Weg : Suchen Sie einfach nach etwas im /proc/$PIDVerzeichnis. Ich verwende in diesem Beispiel "exe", aber Sie können alles andere verwenden.

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

Ihr Code lautet also:

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

Übrigens: Was ist los mit kill -9 $PID || true?


BEARBEITEN:

Nachdem ich ein paar Monate darüber nachgedacht habe ... (ungefähr 24 ...), ist die ursprüngliche Idee, die ich hier gegeben habe, ein netter Hack, aber höchst unportabel. Während einige Implementierungsdetails von Linux vermittelt werden, funktioniert es unter Mac, Solaris oder * BSD nicht. Es kann sogar auf zukünftigen Linux-Kerneln fehlschlagen. Bitte - verwenden Sie "ps" wie in anderen Antworten beschrieben.

elcuco
quelle
Zumindest der Teil kill -9 scheint falsch zu sein (tötet keine
Unterprozesse ab
Warum bekomme ich [: fehlt `] ', wenn ich den ersten Weg benutze?
zehn Meilen
1
/proc/$PID/exeist keine reguläre Datei. Gibt also [ -f /proc/$PID/exe ]immer ein falseErgebnis zurück. Versuchen Sie es [ -h /proc/$PID/exe ].
Alexander Yancharuk
8

Es scheint, als ob du willst

wait $PID

die zurückkehren wird, wenn $pidfertig ist.

Ansonsten können Sie verwenden

ps -p $PID

um zu überprüfen, ob der Prozess noch aktiv ist (dies ist effektiver als kill -0 $pidweil es funktioniert, auch wenn Sie die PID nicht besitzen).

Gagan Gami
quelle
1
Warten ist nicht so effektiv, wie Prozess sollte Kind der aktuellen Shell sein oder es wird geben:pid 123 is not a child of this shell
Calumah
7

Ich denke, das ist eine schlechte Lösung, die sich für die Rennbedingungen öffnet. Was ist, wenn der Prozess zwischen Ihrem Test und Ihrem Aufruf zum Töten abbricht? Dann wird das Töten fehlschlagen. Warum also nicht einfach den Kill in allen Fällen versuchen und seinen Rückgabewert überprüfen, um herauszufinden, wie er gelaufen ist?

entspannen
quelle
+1 Der Exit-Code von kill (1) unterscheidet leider nicht die verschiedenen Fehlersituationen (es sieht so aus, als würde der Exit-Wert für jeden Prozess, den er nicht signalisieren konnte, um eins erhöht). Wenn es dem OP nichts ausmacht, einen eigenen kill (2) -Wrapper zu schreiben, kann er ihn nach einem fehlgeschlagenen kill (2) -Aufruf mit unterschiedlichen Werten beenden, die auf dem Wert von ERRNO basieren.
Nur jemand
Im Moment mache ich nur Kill -9 ohne Prüfung - ich bekomme nur die Fehlermeldung "Prozess existiert nicht", wenn er nicht existiert, was nicht sehr ordentlich ist. Wie würde ich testen, was passiert ist?
Richard H
14
Nicht nachlässig kill -9. Das beendet den Prozess sofort und gibt ihm keine Chance, nach sich selbst aufzuräumen. Verwenden Sie stattdessen das, killwas äquivalent zu ist kill -15. Wenn das nicht funktioniert, sollten Sie herausfinden, warum und nur als letztes Mittel kill -9.
Christoffer Hammarström
0

Hier speichere ich die PID in einer Datei namens .pid (ähnlich wie / run / ...) und führe das Skript nur aus, wenn es nicht bereits ausgeführt wird.

#!/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

Hinweis: Es gibt eine Race-Bedingung, da nicht überprüft wird, wie diese PID aufgerufen wird. Wenn das System neu gestartet wird und .pid vorhanden ist, aber von einer anderen Anwendung verwendet wird, kann dies zu „unvorhergesehenen Konsequenzen“ führen.

invalidmagic
quelle
0

In GNU / Linux können Sie beispielsweise Folgendes verwenden:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Oder so ähnlich

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

und das zeigt dir den Namen der App, nur den Namen ohne ID.

inukaze
quelle
1
pidofgibt keine negative Zahl zurück, da eine negative PID keinen Sinn ergibt und Sie nicht töten können init, sodass Ihre Bedingung keinen Sinn ergibt (und außerdem müssten Sie der entkommen >, um zu verhindern, dass sie eine Umleitung durchführt). Sie möchten nach einem leeren Ergebnis suchen, pidoflegen aber wie jedes anständige Tool einen Exit-Code fest, der Ihnen sagt, ob es funktioniert hat. Die richtige Lösung ist also if Pid=$(pidof 'process_name'); then ...oder (wenn Sie den Wert Pidspäter nicht benötigen ) einfachif pidof 'process_name'; then...
Tripleee
@tripleee hat recht, das pidofBeispiel ist voller Missverständnisse darüber, wie Bash testfunktioniert. gnu.org/software/bash/manual/html_node/…
Bruno Bronosky
0

Der folgende Code prüft, ob mein Prozess ausgeführt wird. Wenn ja, tun Sie nichts.

Lassen Sie uns stündlich und nur dann neue Nachrichten von Amazon SQS überprüfen, wenn der Prozess nicht ausgeführt wird.

#!/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
quelle