it-swarm.com.de

Warten Sie, bis der Vorgang abgeschlossen ist

Gibt es in bash ein eingebautes Feature, das darauf wartet, dass ein Prozess abgeschlossen wird? ____ Der Befehl wait erlaubt es nur einem, auf untergeordnete Prozesse zu warten zu beenden, bevor Sie in einem Skript fortfahren.

Ein mechanischer Weg, dies zu tun, ist wie folgt, aber ich würde gerne wissen, ob in bash ein eingebautes Feature vorhanden ist.

while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
107
Biswajyoti Das

Es gibt kein eingebautes. Verwenden Sie kill -0 in einer Schleife für eine durchführbare Lösung:

anywait(){

    for pid in "[email protected]"; do
        while kill -0 "$pid"; do
            sleep 0.5
        done
    done
}

Oder als einfacheres Oneliner für die einfache einmalige Verwendung:

while kill -0 PIDS 2> /dev/null; do sleep 1; done;

Wie von mehreren Kommentatoren angemerkt, haben Sie, wenn Sie auf Prozesse warten möchten, für die Sie keine Berechtigung zum Senden von Signalen haben, eine andere Möglichkeit gefunden, um zu ermitteln, ob der Prozess ausgeführt wird, um den Aufruf kill -0 $pid zu ersetzen. Unter Linux funktioniert test -d "/proc/$pid", auf anderen Systemen müssen Sie möglicherweise pgrep (falls verfügbar) oder etwas wie ps | grep ^$pid verwenden.

74
Teddy

Warten, bis ein Prozess abgeschlossen ist

Linux:

tail --pid=$pid -f /dev/null

Darwin (erfordert, dass $pid geöffnete Dateien hat):

lsof -p $pid +r 1 &>/dev/null

Mit Timeout (Sekunden)

Linux:

timeout $timeout tail --pid=$pid -f /dev/null

Darwin (erfordert, dass $pid geöffnete Dateien hat):

lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
65
Rauno Palosaari

Ich habe festgestellt, dass "kill -0" nicht funktioniert, wenn der Prozess root (oder anderes) gehört. Daher habe ich pgrep verwendet und Folgendes gefunden:

while pgrep -u root process_name > /dev/null; do sleep 1; done

Dies hätte den Nachteil, dass wahrscheinlich Zombie-Prozesse übereinstimmen.

48
mp3foley

Diese Bash-Skriptschleife endet, wenn der Prozess nicht vorhanden ist oder wenn es sich um einen Zombie handelt.

PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
    sleep 1
done

EDIT: Das obige Skript wurde unter von Rockallite angegeben. Vielen Dank!

Meine ursprüngliche Antwort unten funktioniert für Linux und basiert auf procfs, d. H. /proc/. Ich weiß nicht, ob es portabel ist:

while [[ ( -d /proc/$PID ) && ( -z `grep zombie /proc/$PID/status` ) ]]; do
    sleep 1
done

Es ist nicht auf Shell beschränkt, aber Betriebssysteme selbst haben keine Systemaufrufe, um die Beendigung von Prozessen zu überwachen.

28
teika kazura

FreeBSD und Solaris haben dieses praktische pwait(1)-Dienstprogramm, das genau das macht, was Sie wollen.

Ich glaube, dass auch andere moderne Betriebssysteme die erforderlichen Systemaufrufe haben (MacOS implementiert beispielsweise die kqueue von BSD), aber nicht alle machen es über die Befehlszeile verfügbar.

11
Mikhail T.

Von der bash-Manpage 

   wait [n ...]
          Wait for each specified process and return its termination  status
          Each  n  may be a process ID or a job specification; if a
          job spec is given, all processes  in  that  job's  pipeline  are
          waited  for.  If n is not given, all currently active child processes
          are waited for, and the return  status  is  zero.   If  n
          specifies  a  non-existent  process or job, the return status is
          127.  Otherwise, the return status is the  exit  status  of  the
          last process or job waited for.
10
Charlweed

Alle diese Lösungen werden in Ubuntu 14.04 getestet:

Lösung 1 (mit dem Befehl ps): Um die Antwort von Pierz zusammenzurechnen, würde ich vorschlagen:

while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done

In diesem Fall stellt grep -vw grep sicher, dass grep nur mit Prozessname und nicht mit grep übereinstimmt. Es hat den Vorteil, dass es die Fälle unterstützt, in denen sich der Prozessname nicht am Ende einer Zeile bei ps axg befindet.

Lösung 2 (unter Verwendung des Befehls- und Prozessnamens top):

while [[ $(awk '$12=="process_name" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done

Ersetzen Sie process_name durch den Prozessnamen, der in top -n 1 -b angezeigt wird. Bitte bewahren Sie die Anführungszeichen auf.

Um die Liste der Prozesse anzuzeigen, auf die Sie warten, bis sie abgeschlossen sind, können Sie Folgendes ausführen:

while : ; do p=$(awk '$12=="process_name" {print $0}' <(top -n 1 -b)); [[ $b ]] || break; echo $p; sleep 1; done

Lösung 3 (mit top Befehl und Prozess-ID):

while [[ $(awk '$1=="process_id" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done

Ersetzen Sie process_id durch die Prozess-ID Ihres Programms.

5
Saeid BK

Okay, die Antwort lautet: Nein, es gibt kein eingebautes Werkzeug.

Nachdem Sie /proc/sys/kernel/yama/ptrace_scope auf 0 eingestellt haben, können Sie das Programm strace verwenden. Weitere Schalter können verwendet werden, um das Gerät stumm zu schalten, sodass es wirklich passiv wartet:

strace -qqe '' -p <PID>
5
emu

Ich habe ein kleines Dienstprogramm gefunden, das auf eine PID wartet und sofort zurückkehrt, wenn die PID stirbt.

https://github.com/izabera/waiter

Es ist eine kleine C-Datei, die Sie mit gcc kompilieren können.

#define _GNU_SOURCE
#include <sys/ptrace.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
  if (argc == 1) return 1;
  pid_t pid = atoi(argv[1]);
  if (ptrace(PTRACE_SEIZE, pid, NULL, NULL) == -1) return 1;
  siginfo_t sig;
  return waitid(P_PID, pid, &sig, WEXITED|WNOWAIT);
}

Es funktioniert genauso wie ein Debugger, wenn er an einen Prozess angehängt wird.

3
Mark L. Smith

Es gibt keine integrierte Funktion, die wartet, bis ein Prozess abgeschlossen ist.

Sie können kill -0 an jede gefundene PID senden, damit Sie nicht durch Zombies und Dinge, die in ps noch sichtbar sind, verwirrt werden (während Sie die PID-Liste weiterhin mit ps abrufen).

2
TheBonsai

Hatte das gleiche Problem, löste ich das Problem, das den Prozess abbrach und darauf wartete, dass jeder Prozess mit dem PROC-Dateisystem beendet wurde:

while [ -e /proc/${pid} ]; do sleep 0.1; done
0
littlebridge

Auf einem System wie OSX verfügen Sie möglicherweise nicht über pgrep, sodass Sie diesen Ansatz ausprobieren können, wenn Sie nach Prozessen anhand des Namens suchen:

while ps axg | grep process_name$ > /dev/null; do sleep 1; done

Das $-Symbol am Ende des Prozessnamens stellt sicher, dass grep in der ps-Ausgabe nur mit dem Zeilenende in der Ausgabe von ps und nicht mit sich selbst übereinstimmt.

0
Pierz