wstrzymywanie skryptu bash do zakończenia poprzednich poleceń

Mam skrypt basha, 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 pierwszy zestaw zadań do zakończenia przed rozpoczęciem nowego zestawu. Ale z powodu nohup wydaje się, że wszystkie działają jednocześnie.

Mam nohup, ponieważ zdalnie loguję się do mojego serwera i rozpoczynam tam zadania, a następnie zamykam bash. Czy jest jakieś alternatywne rozwiązanie?

Komentarze

  • Przeszukaj podręcznik dla wbudowanego wait.

Odpowiedź

Będziesz chciał użyć polecenia wait, aby zrób to za siebie. Możesz albo przechwycić wszystkie podrzędne identyfikatory procesów i poczekać na nie specjalnie, albo jeśli są to jedyne procesy w tle, które tworzy twój skrypt, możesz po prostu zadzwonić pod numer wait bez 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" 

Odpowiedź

Kilka punktów:

  • Jeśli celem nohup jest zapobieżenie zabiciu procesów roboczych przez zdalne wyjście powłoki, powinieneś użyć nohup w samym skrypcie, a nie w poszczególnych procesach roboczych, które tworzy.

  • Jak wyjaśniono tutaj , nohup zapobiega tylko otrzymywaniu przez procesy SIGHUP i od interakcji z terminalem, ale nie przerywa relacji między powłoką a jej procesami potomnymi.

  • Z powodu powyższego punktu, z , prosta wait pomiędzy dwiema for pętlami spowoduje, że druga for do wykonania dopiero po zakończeniu wszystkich procesów potomnych uruchomionych przez pierwszy for.

  • Za pomocą prostego wait:

    oczekiwane są wszystkie aktualnie aktywne procesy potomne, a stan powrotu wynosi zero.

  • Jeśli musisz uruchomić drugi for tylko wtedy, gdy nie było błędów w pierwszym , wtedy „będziesz musiał zapisać każdy PID pracownika za pomocą $! i przekazać je wszystkie do wait:

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

Komentarze

  • Jest ld będą innymi zadaniami uruchomionymi na serwerze. Więc ' d chcę tylko czekać na moją partię… są to skrypty R, więc są uruchamiane pod R lub cc1plus w top poleceniu
  • Również ' chciałbym używać nohup w środku aby uruchomić wszystkie polecenia z " parallel ". w zasadzie są to symulacje programu naukowego. Chcę przeprowadzić łącznie 180 symulacji, ale w partiach po 60. Licznik również musi przejść od 1 do 180. Jeśli wykonam je pojedynczo, zajmie to zbyt dużo czasu.
  • wait powoduje, że bash czeka na zadania w tle, które się uruchomiło, nic więcej. Może być tu trochę zamieszania – te for pętle, czy zapisałeś je do pliku i wywołałeś jako skrypt (jak założyłem, z powodu ##script), czy też wpisujesz je ręcznie w terminalu?
  • robiłem cat file.txt | while, a identyfikatory nie zostały ustawione poza pętlą więc polecenie wait zobaczyło pusty ciąg $pids. dlaczego tak się dzieje, omówiono na serverfault.com/q/259339 . łatwo naprawione jako while ... < files.txt zgodnie z odpowiedzią na serverfault.com/a/259346
  • Po prostu ciekawy jaki jest cel znaku + ze zmienną pids?

Odpowiedź

Użyj fg wbudowany. Czeka do zakończenia procesów w tle.

Spróbuj help fg, aby uzyskać szczegółowe informacje.

Komentarze

  • Skrypt działa bez kontroli zadań.

Odpowiedź

Jeśli wstawisz coś takiego jak następujący segment kodu Pomiędzy dwoma pętlami for, 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 aplikacja Rscript ma szansę nie zakończyć się pomyślnie i pozostanie w pobliżu, twoja druga pętla for może nie mieć szansy na uruchomienie. Segment kodu powyżej zakłada, że wszystkie procesy z identyfikatorem Rscript --vanilla zakończą się i znikną prawidłowo. Nie wiedząc, co robi Twoja aplikacja i jak działa, muszę oprzeć się na tym założeniu.

EDYTUJ

W świetle komentarzy lepiej byłoby Twoje potrzeby. (zawiera oryginalny kod oraz 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 

Komentarze

  • Proces name w top pokazuje czasem R lub cc1plus.
  • W takim przypadku będziesz musiał znaleźć wspólny mianownik, który pojawi się na liście ps -ef. Lub po każdym poleceniu nohup zapisz PID do zmiennej (najlepiej tablicy) przez echo ${!} i sprawdź tę grupę PIDów. Kiedy wszystkie znikną, możesz przejść do drugiej for pętli

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *