wstrzymywanie skryptu bash do momentu zakończenia poprzednich poleceń


20

Mam skrypt bash, który wygląda następująco:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Chciałbym utworzyć kolejną pętlę for po pierwszej, aby kontynuować przez kolejne 30. Na przykład

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Chciałbym, aby pierwszy zestaw zadań zakończył się przed rozpoczęciem nowego zestawu. Ale z tego nohuppowodu wydaje się, że wszystkie działają jednocześnie.

Mam, nohupponieważ zdalnie loguję się na mój serwer i uruchamiam tam zadania, a następnie zamykam bash. Czy istnieje alternatywne rozwiązanie?


1
Wyszukaj w instrukcji waitwbudowane.
Satō Katsura,

Odpowiedzi:


22

Będziesz chciał użyć tego waitpolecenia, aby zrobić to za Ciebie. Możesz przechwycić wszystkie identyfikatory procesów potomnych i poczekać na nie, lub jeśli są to jedyne procesy w tle tworzone przez skrypt, możesz po prostu zadzwonić waitbez argumentu. Na przykład:

#!/bin/bash
# run two processes in the background and wait for them to finish

nohup sleep 3 &
nohup sleep 10 &

echo "This will wait until both are done"
date
wait
date
echo "Done"

6

Kilka punktów:

  • Jeśli Twoim celem nohupjest zapobieganie zabijaniu procesów roboczych przez zdalną powłokę, powinieneś użyć nohupsamego skryptu, a nie poszczególnych tworzonych przez niego procesów roboczych.

  • Jak wyjaśniono tutaj , nohuptylko uniemożliwia procesom otrzymywanie SIGHUP i interakcję z terminalem, ale nie przerywa relacji między powłoką a jej procesami potomnymi.

  • Z powodu powyższego punktu, z lub bez nohup, prosta waitmiędzy dwiema forpętlami spowoduje, że druga forzostanie wykonana dopiero po zakończeniu wszystkich procesów potomnych rozpoczętych przez pierwszą for.

  • Prostym wait:

    wszystkie aktualnie aktywne procesy potomne są oczekiwane, a zwracany status to zero.

  • Jeśli musisz uruchomić drugi, fortylko jeśli nie wystąpiły błędy w pierwszym, musisz zapisać każdy identyfikator PID pracownika $!i przekazać je wszystkim wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }

Na serwerze mogą działać inne zadania. Więc chciałbym tylko czekać na moją partię. Są to skrypty R, więc są uruchamiane pod komendą Rlub cc1plusw topkomendzie
masfenix

Chciałbym również użyć nohup wewnątrz, aby uruchomić wszystkie polecenia w trybie „równoległym”. w zasadzie są to symulacje programu naukowego. Chcę uruchomić w sumie 180 symulacji, ale w partiach po 60. Licznik również musi przejść od 1 do 180. Jeśli zrobię to pojedynczo, potrwa to zbyt długo.
masfenix

waitpowoduje bashoczekiwanie na zadania w tle, które sam się pojawił, nic więcej. Może to być pewne zamieszanie - te forpętle, czy zapisałeś je do pliku i wywołałeś jako skrypt (co założyłem, ze względu na ##scriptlinię), czy wpisujesz je ręcznie w terminalu?
Matei David,

-1

Użyj fgwbudowanego. Czeka na zakończenie procesów w tle.

Spróbuj help fgpo szczegóły.


Skrypt działa bez kontroli zadań.
Kusalananda

-1

Jeśli wstawisz coś takiego jak poniższy segment kodu między dwiema forpętlami, może to pomóc.

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

Oczywiście, jeśli Twoja aplikacja Rscriptma szansę nie ukończyć się pomyślnie i pozostać w tyle, druga pętla for może nie mieć szansy na uruchomienie. Powyższy segment kodu zakłada, że ​​wszystkie procesy z identyfikatorem Rscript --vanillazakończą się i znikną poprawnie. Nie wiedząc, co robi Twoja aplikacja i jak działa, muszę polegać na tym założeniu.

EDYTOWAĆ

W świetle komentarzy lepiej to spełni twoje potrzeby. (zawiera twój oryginalny kod, a także logikę sprawdzania ukończenia)

for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
pids[$i]=${!}
done

flag=0

while [ flag -eq 0 ] 
do
  for PID in $(echo ${pids[@]})
  do
    flag=1
    ps -ef | grep ${PID} | grep -v grep >/dev/null; r=${?}
    if [ ${r} -eq 0 ]
    then 
      flag=0
    fi
  done
done

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Nazwa procesu w toppokazuje albo Rczasami albo cc1plus.
masfenix

W takim przypadku musisz znaleźć wspólny mianownik, który pojawi się na ps -efliście. Lub po każdym nohuppoleceniu zapisz PID do zmiennej (najlepiej tablicy) według echo ${!}i sprawdź tę grupę PID. Gdy wszystkie znikną, możesz przejść do drugiej forpętli
MelBurslan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.