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
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 dwiemafor
pętlami spowoduje, że drugafor
do wykonania dopiero po zakończeniu wszystkich procesów potomnych uruchomionych przez pierwszyfor
. -
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 dowait
: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
lubcc1plus
wtop
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, żebash
czeka na zadania w tle, które się uruchomiło, nic więcej. Może być tu trochę zamieszania – tefor
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 jakowhile ... < 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 czasemR
lubcc1plus
. - W takim przypadku będziesz musiał znaleźć wspólny mianownik, który pojawi się na liście
ps -ef
. Lub po każdym poleceniunohup
zapisz PID do zmiennej (najlepiej tablicy) przezecho ${!}
i sprawdź tę grupę PIDów. Kiedy wszystkie znikną, możesz przejść do drugiejfor
pętli
wait
.