Wacht tot een proces is voltooid

Is er een ingebouwde functie in Bash om te wachten tot een proces is voltooid?

Met de opdracht waitkan 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 $pidopen 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 $pidopen 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 -0in 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 grepervoor 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_namedoor de procesnaam die in top -n 1 -bstaat. 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_iddoor 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_scopeop 0, is het mogelijk om het programma stracete 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 waitin 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 -0in 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 sleeptijd, 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 -0kunnen 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.

Other episodes