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.