Attendre la fin de "n'importe quel processus"
y a-t-il une fonctionnalité intégrée à bash pour attendre la fin du processus?
La commande wait
permet seulement d'attendre la fin des processus enfants.
Je voudrais savoir si il y a moyen d'attendre pour tout processus à terminer avant de passer dans n'importe quel script.
Une mécanique façon de le faire est comme suit, mais je voudrais savoir s'il est construit en fonction de bash.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
13 réponses
il n'y a pas de bâtiment. Utilisez kill -0
dans une boucle pour une solution utilisable:
anywait(){
for pid in "$@"; do
while kill -0 "$pid"; do
sleep 0.5
done
done
}
ou comme un oneliner plus simple pour une utilisation facile une fois:
while kill -0 PIDS 2> /dev/null; do sleep 1; done;
comme l'ont noté plusieurs commentateurs, si vous voulez attendre des processus auxquels vous n'avez pas le privilège d'envoyer des signaux, vous devez trouver un autre moyen de détecter si le processus est en cours d'exécution pour remplacer l'appel kill -0 $pid
. Sur Linux, test -d "/proc/$pid"
fonctionne, sur d'autres systèmes vous peut-être utiliser pgrep
(si disponible) ou quelque chose comme ps | grep ^$pid
.
d'attendre la fin de n'importe quel processus
Linux:
tail --pid=$pid -f /dev/null
Darwin (exige que $pid
ait des fichiers ouverts):
lsof -p $pid +r 1 &>/dev/null
Avec délai d'attente (en secondes)
Linux:
timeout $timeout tail --pid=$pid -f /dev/null
Darwin (exige que $pid
ait des fichiers ouverts):
lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
j'ai trouvé "kill -0" ne fonctionne pas si le processus appartient à root (ou autre), donc j'ai utilisé pgrep et est venu avec:
while pgrep -u root process_name > /dev/null; do sleep 1; done
cela aurait l'inconvénient de correspondre probablement processus zombie.
cette boucle bash script se termine si le processus n'existe pas, ou si c'est un zombie.
PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
sleep 1
done
EDIT : le script ci-dessus a été donné ci-dessous par Rockallite . Merci!
ma réponse originale ci-dessous fonctionne pour Linux, en se basant sur procfs
i.e. /proc/
. Je ne connais pas sa portabilité:
while [[ ( -d /proc/$PID ) && ( -z `grep zombie /proc/$PID/status` ) ]]; do
sleep 1
done
ce n'est pas limité à shell, mais OS's ils n'ont pas eux-mêmes d'appels système pour surveiller la fin du processus sans enfant.
à Partir de la page de manuel de bash
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.
FreeBSD et Solaris ont cet utilitaire pratique pwait(1)
, qui fait exactement ce que vous voulez.
je crois, d'autres OS modernes ont aussi les appels système nécessaires (MacOS, par exemple, met en œuvre BSD kqueue
), mais tous ne le rendent pas disponible en ligne de commande.
Ok, donc il semble que la réponse est -- non, il n'y a pas d'outil intégré.
après avoir réglé /proc/sys/kernel/yama/ptrace_scope
sur 0
, il est possible d'utiliser le programme strace
. D'autres interrupteurs peuvent être utilisés pour la rendre silencieuse, de sorte qu'elle attend vraiment passivement:
strace -qqe '' -p <PID>
toutes ces solutions sont testées dans Ubuntu 14.04:
Solution 1 (en utilisant la commande ps): Juste pour ajouter à la réponse de Pierz, je suggérerais:
while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done
dans ce cas, grep -vw grep
garantit que grep ne correspond qu'à process_name et pas à grep lui-même. Il a l'avantage de supporter les cas où le nom de processus n'est pas à la fin d'une ligne à ps axg
.
Solution 2 (en utilisant la commande supérieure et le nom du procédé):
while [[ $(awk '=="process_name" {print "151910920"}' <(top -n 1 -b)) ]]; do sleep 1; done
remplacer process_name
par le nom du procédé qui apparaît dans top -n 1 -b
. Veuillez conserver les guillemets.
pour voir la liste des processus que vous attendez qu'ils soient terminés, vous pouvez lancer:
while : ; do p=$(awk '=="process_name" {print "151920920"}' <(top -n 1 -b)); [[ $b ]] || break; echo $p; sleep 1; done
Solution 3 (en utilisant la commande supérieure et le numéro de processus):
while [[ $(awk '=="process_id" {print "151930920"}' <(top -n 1 -b)) ]]; do sleep 1; done
remplacer process_id
avec l'identifiant du processus de votre programme.
j'ai trouvé un petit utilitaire qui attend sur n'importe quel PID et retourne immédiatement quand le PID meurt.
https://github.com/izabera/waiter
c'est un petit fichier C que vous pouvez compiler avec gcc.
#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);
}
cela fonctionne de la même manière qu'un débogueur quand il s'attache à un processus.
il n'y a pas de fonctionnalité intégrée pour attendre la fin de n'importe quel processus.
vous pouvez envoyer des kill -0 à n'importe quel PID trouvé, de sorte que vous ne soyez pas déconcerté par les zombies et les choses qui seront encore visibles dans ps (tout en récupérant la liste PID en utilisant ps).
sur un système comme OSX vous pourriez ne pas avoir pgrep donc vous pouvez essayer cette évaluation, en recherchant des processus par nom:
while ps axg | grep process_name$ > /dev/null; do sleep 1; done
le symbole $
à la fin du nom du processus garantit que grep ne correspond que process_name à la fin de la ligne dans la sortie ps et pas lui-même.
avait le même problème, j'ai résolu le problème en tuant le processus et en attendant que chaque processus se termine en utilisant le système de fichiers PROC:
while [ -e /proc/${pid} ]; do sleep 0.1; done
solution de blocage
utiliser le wait
dans une boucle, pour attendre terminer tous les processus:
function anywait()
{
for pid in "$@"
do
wait $pid
echo "Process $pid terminated"
done
echo 'All processes terminated'
}
cette fonction disparaîtra immédiatement, lorsque tous les processus auront été interrompus. C'est la solution la plus efficace.
Non-solution de blocage
utiliser le kill -0
dans une boucle, pour attendre terminer tous les processus + faire n'importe quoi entre les contrôles:
function anywait_w_status()
{
for pid in "$@"
do
while kill -0 "$pid"
do
echo "Process $pid still running..."
sleep 1
done
done
echo 'All processes terminated'
}
le temps de réaction est passé à sleep
parce qu'il faut éviter une forte utilisation de CPU.
un usage réaliste:
en Attente pour mettre fin à tous les processus + informer l'utilisateur sur tous running PIDs.
function anywait_w_status2()
{
while true
do
alive_pids=()
for pid in "$@"
do
kill -0 "$pid" 2>/dev/null \
&& alive_pids+="$pid "
done
if [ ${#alive_pids[@]} -eq 0 ]
then
break
fi
echo "Process(es) still running... ${alive_pids[@]}"
sleep 1
done
echo 'All processes terminated'
}
Notes
ces fonctions reçoivent les PIDs via les arguments par $@
comme tableau de BASH.