een bash-script pauzeren totdat eerdere opdrachten zijn voltooid

Ik heb een bash-script dat er als volgt uitziet:

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

Ik zou graag nog een for-lus willen maken na de eerste om door te gaan voor nog eens 30. Bijvoorbeeld

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

Ik zou graag willen dat de eerste set taken die moeten worden voltooid voordat met de nieuwe set wordt begonnen. Maar vanwege de nohup lijkt het erop dat ze allemaal tegelijkertijd worden uitgevoerd.

Ik heb nohup omdat ik op afstand inlog op mijn server en de jobs daar start en daarna mijn bash sluit. Is er een alternatieve oplossing?

Reacties

  • Zoek in de handleiding naar de wait ingebouwde.

Answer

U “wilt het wait commando gebruiken om doe dit voor u. U kunt ofwel alle onderliggende proces-IDs vastleggen en specifiek op ze wachten, of als dit de enige achtergrondprocessen zijn die uw script maakt, kunt u wait bellen zonder argument. Bijvoorbeeld:

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

Antwoord

Een paar punten:

  • Als uw doel met nohup is om te voorkomen dat een externe shell-exit uw werkprocessen vernietigt, moet u op het script zelf, niet op de individuele werkprocessen die het maakt.

  • Zoals hier uitgelegd , nohup voorkomt alleen dat processen SIGHUP ontvangen en van interactie met de terminal, maar het verbreekt de relatie tussen de shell en zijn onderliggende processen niet.

  • Vanwege het bovenstaande punt, met of zonder nohup, een simpele wait tussen de twee for lussen zal de tweede for moet alleen worden uitgevoerd nadat alle onderliggende processen die zijn gestart door de eerste for zijn afgesloten.

  • Met een eenvoudige wait:

    er wordt op alle momenteel actieve onderliggende processen gewacht en de retourstatus is nul.

  • Als u de tweede for alleen moet uitvoeren als er geen fouten in de eerste , dan “moet je elke werker-PID opslaan met $!, en ze allemaal doorgeven aan wait:

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

Reacties

  • Er kan Het zouden andere taken zijn die op de server draaien. Dus ik ' wil alleen maar wachten op mijn batch .. het zijn R-scripts, dus ze worden uitgevoerd onder R of cc1plus in het top commando
  • Ook ' wil ik nohup binnen gebruiken om alle opdrachten in " parallel " uit te voeren. in feite zijn dit simulaties voor een wetenschappelijk programma. Ik wil in totaal 180 simulaties uitvoeren, maar in batches van 60. De teller moet ook van 1 naar 180 gaan. Als ik ze een voor een doe, duurt het te lang.
  • wait zorgt ervoor dat bash wacht op de achtergrondtaken die het zelf heeft voortgebracht, niets anders. Er kan hier enige verwarring ontstaan: deze for lussen, heb je ze in een bestand opgeslagen en ze aangeroepen als een script (wat ik aannam, vanwege de ##script regel), of typ je ze met de hand in de terminal?
  • ik deed cat file.txt | while en de pids was niet buiten de lus geplaatst dus het wait commando zag een lege $pids string. waarom dit gebeurt, wordt besproken op serverfault.com/q/259339 . eenvoudig te repareren als while ... < files.txt zoals beantwoord op serverfault.com/a/259346
  • Gewoon nieuwsgierig wat is het doel van + teken met pids-variabele?

Antwoord

Gebruik de fg ingebouwd. Het wacht totdat de achtergrondprocessen zijn voltooid.

Probeer help fg voor details.

Reacties

  • Een script wordt uitgevoerd zonder taakcontrole.

Antwoord

Als u zoiets als het volgende codesegment invoegt tussen je twee for loops, kan het helpen.

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

Natuurlijk, als je applicatie Rscript heeft een kans om niet succesvol af te ronden en te blijven hangen, je tweede for-lus heeft misschien geen kans om te draaien. Het bovenstaande codesegment gaat ervan uit dat alle processen met de identificatie Rscript --vanilla zullen worden voltooid en correct zullen verdwijnen. Zonder te weten wat uw applicatie doet en hoe deze werkt, moet ik op deze aanname vertrouwen.

EDIT

In het licht van de commentaren zou dit beter passen je behoeften. (het bevat zowel uw originele code als logica voor het controleren van de voltooiing)

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 

Opmerkingen

  • Het proces naam in top toont ofwel R soms of cc1plus.
  • In dat geval moet u een gemeenschappelijke noemer vinden, die wordt weergegeven in de lijst ps -ef. Of neem na elk nohup -commando de PID op in een variabele (bij voorkeur een array) door echo ${!} en controleer op deze groep PIDs. Als ze allemaal verdwijnen, kun je doorgaan naar de tweede for lus

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *