Is er een ingebouwde functie in Bash om te wachten tot een proces is voltooid?
Met de opdracht wait
kan men alleen wachten tot de onderliggende processen zijn voltooid.
Ik zou graag willen weten of er een manier is om te wachten tot een proces is voltooid voordat ik verder ga in een script.
Een mechanische manier om dit te doen is als volgt, maar ik zou graag willen weten of er een ingebouwde functie in Bash is.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Antwoord 1, autoriteit 100%
Wachten tot een proces is voltooid
Linux:
tail --pid=$pid -f /dev/null
Darwin (vereist dat $pid
open bestanden heeft):
lsof -p $pid +r 1 &>/dev/null
Met time-out (seconden)
Linux:
timeout $timeout tail --pid=$pid -f /dev/null
Darwin (vereist dat $pid
open bestanden heeft):
lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
Antwoord 2, autoriteit 45%
Er is geen ingebouwd. Gebruik kill -0
in een lus voor een werkbare oplossing:
anywait(){
for pid in "$@"; do
while kill -0 "$pid"; do
sleep 0.5
done
done
}
Of als een eenvoudigere oneliner voor eenvoudig eenmalig gebruik:
while kill -0 PIDS 2> /dev/null; do sleep 1; done;
Zoals opgemerkt door verschillende commentatoren, moet je, als je wilt wachten op processen waar je niet het voorrecht hebt om signalen naar te sturen, een andere manier vinden om te detecteren of het proces loopt om de kill -0 $pid
-oproep. Op Linux werkt test -d "/proc/$pid"
, op andere systemen moet je misschien pgrep
(indien beschikbaar) of iets als ps | grep "^$pid "
.
Antwoord 3, autoriteit 28%
Ik ontdekte dat “kill -0” niet werkt als het proces eigendom is van root (of iets anders), dus ik gebruikte pgrep en bedacht:
while pgrep -u root process_name > /dev/null; do sleep 1; done
Dit zou het nadeel hebben dat het waarschijnlijk overeenkomt met zombieprocessen.
Antwoord 4, autoriteit 16%
Deze bash-scriptlus eindigt als het proces niet bestaat of als het een zombie is.
PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
sleep 1
done
EDIT: het bovenstaande script was hieronder gegevendoor Rockallite. Bedankt!
Mijn oorspronkelijke antwoord hieronder werkt voor Linux en vertrouwt op procfs
, d.w.z. /proc/
. Ik weet de draagbaarheid niet:
while [[ ( -d /proc/$PID ) && ( -z `grep zombie /proc/$PID/status` ) ]]; do
sleep 1
done
Het is niet beperkt tot shell, maar de besturingssystemen zelf hebben geen systeemaanroepen om de beëindiging van niet-onderliggende processen te bekijken.
Antwoord 5, autoriteit 8%
FreeBSD en Solaris hebben dit handige hulpprogramma pwait(1)
, dat precies doet wat u wilt.
Ik geloof dat andere moderne besturingssystemen ook de nodige systeemaanroepen hebben (MacOS, bijvoorbeeld, implementeert BSD’s kqueue
), maar niet alle maken het beschikbaar vanaf de opdrachtregel.
Antwoord 6, autoriteit 6%
Van de bash-manpagina
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.
Antwoord 7, autoriteit 3%
Al deze oplossingen zijn getest in Ubuntu 14.04:
Oplossing 1 (met het ps-commando):
Om het antwoord van Pierz aan te vullen, zou ik willen voorstellen:
while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done
In dit geval zorgt grep -vw grep
ervoor dat grep alleen overeenkomt met process_name en niet met grep zelf. Het heeft het voordeel dat het de gevallen ondersteunt waarin de process_name niet aan het einde van een regel staat op ps axg
.
Oplossing 2 (met gebruik van de bovenste opdracht en procesnaam):
while [[ $(awk '$12=="process_name" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Vervang process_name
door de procesnaam die in top -n 1 -b
staat. Gelieve de aanhalingstekens te behouden.
Als u de lijst met processen wilt zien die u wacht tot ze klaar zijn, kunt u het volgende uitvoeren:
while : ; do p=$(awk '$12=="process_name" {print $0}' <(top -n 1 -b)); [[ $b ]] || break; echo $p; sleep 1; done
Oplossing 3 (met gebruik van het bovenste commando en proces-ID):
while [[ $(awk '$1=="process_id" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Vervang process_id
door de proces-ID van uw programma.
Antwoord 8, autoriteit 3%
Ok, dus het lijkt erop dat het antwoord is — nee, er is geen ingebouwde tool.
Na het instellen van /proc/sys/kernel/yama/ptrace_scope
op 0
, is het mogelijk om het programma strace
te gebruiken. Verdere schakelaars kunnen worden gebruikt om het stil te maken, zodat het echt passief wacht:
strace -qqe '' -p <PID>
Antwoord 9, autoriteit 2%
Blokkeeroplossing
Gebruik de wait
in een lus, om te wachten op het beëindigen van alle processen:
function anywait()
{
for pid in "$@"
do
wait $pid
echo "Process $pid terminated"
done
echo 'All processes terminated'
}
Deze functie wordt onmiddellijk afgesloten wanneer alle processen zijn beëindigd. Dit is de meest efficiënte oplossing.
Niet-blokkerende oplossing
Gebruik de kill -0
in een lus, om te wachten op het beëindigen van alle processen + doe iets tussen de controles:
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'
}
De reactietijd is teruggebracht tot sleep
tijd, omdat hoog CPU-gebruik moet worden voorkomen.
Een realistisch gebruik:
Wachten op het beëindigen van alle processen + informeer de gebruiker over alleactieve PID’s.
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'
}
Opmerkingen
Deze functies krijgen PID’s via argumenten door $@
als bash array.
10, Autoriteit 2%
Er is geen ingebouwde functie om te wachten op elk proces om te voltooien.
U zou kill -0
kunnen verzenden naar een PID, dus u wordt niet verbaasd door zombies en spullen die nog steeds zichtbaar zijn in ps
(terwijl u nog steeds het ophalen de PID-lijst met ps
).
11
Had hetzelfde probleem, ik loste de kwestie op het proces en wachtend op elk proces om te voltooien met behulp van het PROC-bestandssysteem:
while [ -e /proc/${pid} ]; do sleep 0.1; done
12
Gebruik InotifyWAIT om een bestand te controleren dat gesloten is, wanneer uw proces wordt beëindigd. Voorbeeld (op Linux):
yourproc >logfile.log & disown
inotifywait -q -e close logfile.log
-E Geeft het evenement aan om te wachten op, -Q betekent minimale output alleen op beëindiging. In dit geval is het:
logfile.log CLOSE_WRITE,CLOSE
Een opdracht met één wachttijd kan worden gebruikt om te wachten op meerdere processen:
yourproc1 >logfile1.log & disown
yourproc2 >logfile2.log & disown
yourproc3 >logfile3.log & disown
inotifywait -q -e close logfile1.log logfile2.log logfile3.log
De uitgangsreeks van InotifyWait zal u vertellen, welk proces wordt beëindigd. Dit werkt alleen met ‘echte’ bestanden, niet met iets in / proc /
13
Op een systeem zoals OSX heb je misschien geen PGREP, zodat je deze taxoch kunt proberen, wanneer je op zoek bent naar processen op naam:
while ps axg | grep process_name$ > /dev/null; do sleep 1; done
De $
Symbool aan het einde van de procesnaam zorgt ervoor dat Greapp alleen betrekking heeft op Process_Name naar het einde van de lijn in de PS-uitvoer en niet zelf.