întreruperea unui script bash până la finalizarea comenzilor anterioare

Am un script bash care arată după cum urmează:

##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 

Aș dori să creez o altă buclă de for după prima care să continue pentru încă 30. De exemplu

##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 

Aș dori pentru primul set de lucrări care se termină înainte de a începe noul set. Dar din cauza nohup se pare că toate sunt rulate simultan.

Am nohup deoarece mă conectez de la distanță la serverul meu și încep joburile acolo și apoi închid bash-ul. Există o soluție alternativă?

Comentarii

  • Căutați manualul pentru wait integrat.

Răspuns

Veți dori să utilizați comanda wait faceți acest lucru pentru dvs. Puteți fie să capturați toate ID-urile procesate de copii și să le așteptați în mod specific, fie dacă acestea sunt singurele procese de fundal pe care le creează scriptul dvs., puteți apela doar wait fără argument. De exemplu:

#!/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" 

Răspuns

Câteva puncte:

  • Dacă obiectivul dvs. cu nohup este de a împiedica o ieșire de la distanță a shell-ului să omoare procesele lucrătorului dvs., ar trebui să utilizați nohup pe scriptul în sine, nu pe procesele individuale ale lucrătorului pe care le creează.

  • Așa cum se explică aici , nohup împiedică procesele să primească SIGHUP și de la interacțiunea cu terminalul, dar nu rupe relația dintre shell și procesele sale copil.

  • Din cauza punctului de mai sus, cu sau fără nohup, un simplu wait între cele două bucle for va provoca al doilea for să fie executat numai după ce toate procesele secundare începute de primul for au ieșit.

  • Cu un simplu wait:

    toate procesele secundare active în prezent sunt așteptate, iar starea de returnare este zero.

  • Dacă trebuie să rulați al doilea for numai dacă nu au existat erori în primul , atunci va trebui să salvați fiecare PID lucrător cu $! și să le transmiteți tuturor către wait:

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

Comentarii

  • Aș fi alte lucrări care rulează pe server. Deci, ' vreau doar să aștept lotul meu .. sunt scripturi R, deci sunt rulate sub R sau din comanda top
  • De asemenea, îmi place să folosesc nohup în interior pentru a rula toate comenzile din " paralel ". practic acestea sunt simulări pentru un program științific. Vreau să rulez 180 de simulări în total, dar în loturi de 60. Contorul trebuie să treacă și de la 1 la 180. Dacă le fac pe rând, va dura prea mult.
  • wait face ca bash să aștepte lucrările de fundal pe care le-a generat, nimic altceva. S-ar putea să existe o anumită confuzie aici – aceste for bucle, le-ați salvat într-un fișier și le-ați invocat ca un script (ceea ce am presupus, din cauza >

line), sau le tastați manual în terminal?

  • făceam cat file.txt | while și pids nu a fost setat în afara buclei deci comanda de așteptare a văzut un șir $pids gol. de ce se întâmplă acest lucru este discutat la serverfault.com/q/259339 . ușor de remediat ca while ... < files.txt așa cum a răspuns la serverfault.com/a/259346
  • Doar curios care este scopul variabilei + semn cu pids?
  • Răspuns

    Utilizați fg builtin. Se așteaptă până la finalizarea proceselor de fundal.

    Încercați help fg pentru detalii.

    Comentarii

    • Un script rulează fără controlul lucrărilor.

    Răspuns

    Dacă inserați ceva de genul următorului segment de cod între cele două bucle for, ar putea fi de ajutor.

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

    Desigur, dacă aplicația dvs. Rscript are șansa de a nu finaliza cu succes și de a rămâne în jur, secunda dvs. pentru buclă poate să nu aibă șansa de a rula. Segmentul de cod de mai sus presupune că toate procesele cu identificatorul Rscript --vanilla se vor finaliza și vor dispărea corect. Fără să știu ce face și cum rulează aplicația dvs., trebuie să mă bazez pe această ipoteză.

    EDIT

    În lumina comentariilor, acest lucru s-ar potrivi mai bine nevoile tale. (include codul dvs. original, precum și logica de verificare a finalizării)

    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 

    Comentarii

    • Procesul numele din top afișează uneori R uneori sau cc1plus.
    • În acest caz, va trebui să găsiți un numitor comun, care apare în lista ps -ef. Sau după fiecare comandă nohup, înregistrați PID la o variabilă (de preferință o matrice) prin echo ${!} și verificați acest grup de PID-uri. Când dispar toate, puteți trece la a doua buclă for

    Lasă un răspuns

    Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *