Mám bash skript, který vypadá takto:
##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
Chtěl bych vytvořit další smyčku for po první, abych pokračoval dalších 30. Například
##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
Chtěl bych pro první sadu úloh dokončit před spuštěním nové sady. Ale kvůli nohup
se zdá, že jsou všechny spuštěny současně.
Mám nohup
, protože se vzdáleně přihlásím na svůj server a spustím tam úlohy a poté zavřu bash. Existuje alternativní řešení?
Komentáře
Odpovědět
Chcete použít příkaz wait
k udělejte to za vás. Můžete buď zachytit všechny podřízené ID procesů a počkat na ně konkrétně, nebo pokud jsou to jediné procesy na pozadí, které váš skript vytváří, stačí zavolat wait
bez argumentu. Například:
#!/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"
Odpověď
Několik bodů:
-
Pokud je vaším cílem
nohup
zabránit tomu, aby vzdálený výstup shellu zabil vaše pracovní procesy, měli byste použítnohup
na samotný skript, nikoli na jednotlivé pracovní procesy, které vytváří. -
Jak je vysvětleno zde ,
nohup
pouze brání procesům přijímat SIGHUP a od interakce s terminálem, ale nenarušuje vztah mezi shellem a jeho podřízenými procesy. -
Kvůli výše uvedenému bodu, s nebo bez
nohup
, jednoduchéwait
mezi dvěmafor
smyčkami způsobí druhéfor
bude provedeno až poté, co budou ukončeny všechny podřízené procesy spuštěné prvnímifor
. -
S jednoduchým
wait
:čekají se na všechny aktuálně aktivní podřízené procesy a návratový stav je nulový.
-
Pokud potřebujete spustit druhou
for
, pouze pokud v první chybě nebyly žádné chyby , pak „budete muset uložit každý PID pracovníka s$!
a předat je všemwait
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Komentáře
- Tam cou Byly by jiné úlohy spuštěné na serveru. Takže ' chci jen počkat na svou dávku .. jsou to R skripty, takže jsou spuštěny pod
R
nebocc1plus
vtop
příkazu - Také <
bych rád používal nohup uvnitř spustit všechny příkazy v " paralelně ". v zásadě se jedná o simulace vědeckého programu. Chci spustit celkem 180 simulací, ale v dávkách 60. Počítadlo také musí jít od 1 do 180. Pokud je udělám po jednom, bude to trvat příliš dlouho.
wait
způsobí, že bash
počká na úlohy na pozadí, které sama vytvořila, nic jiného. Mohlo by zde dojít k určitému zmatku – tyto smyčky for
, uložili jste je do souboru a vyvolali je jako skript (co jsem předpokládal kvůli ##script
line), nebo je píšete ručně do terminálu? cat file.txt | while
a pids nebyl nastaven mimo smyčku příkaz čekání tedy viděl prázdný $pids
řetězec. proč se to stane, je popsáno na serverfault.com/q/259339 . snadno opravitelné jako while ... < files.txt
podle odpovědi na serverfault.com/a/259346 odpověď
Použijte fg
vestavěné. Čeká na dokončení procesů na pozadí.
Podrobnosti zkuste help fg
.
Komentáře
- Skript běží bez kontroly úlohy.
Odpovědět
Pokud vložíte něco jako následující segment kódu mezi vašimi dvěma for
smyčkami by to mohlo pomoci.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Samozřejmě, pokud vaše aplikace Rscript
má šanci, že se nedokončí úspěšně a přetrvává, vaše druhá smyčka for nemusí mít šanci se spustit. Výše uvedený segment kódu předpokládá, že všechny procesy s identifikátorem Rscript --vanilla
se dokončí a zmizí správně. Aniž bych věděl, co vaše aplikace dělá a jak běží, musím se na tento předpoklad spolehnout.
EDIT
Ve světle komentářů by to lépe vyhovovalo tvoje potřeby. (zahrnuje váš původní kód i logiku kontroly dokončení)
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
Komentáře
- Proces název v
top
zobrazuje buďR
někdy, nebocc1plus
. - V takovém případě budete muset najít společného jmenovatele, který se zobrazí v seznamu
ps -ef
. Nebo po každémnohup
příkazu nahrajte PID do proměnné (nejlépe do pole) pomocíecho ${!}
a zkontrolujte tuto skupinu PID. Když všechny zmizí, můžete přejít do druhéfor
smyčky
wait
.