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
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 simpelewait
tussen de tweefor
lussen zal de tweedefor
moet alleen worden uitgevoerd nadat alle onderliggende processen die zijn gestart door de eerstefor
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 aanwait
: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
ofcc1plus
in hettop
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 datbash
wacht op de achtergrondtaken die het zelf heeft voortgebracht, niets anders. Er kan hier enige verwarring ontstaan: dezefor
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 alswhile ... < 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 ofwelR
soms ofcc1plus
. - In dat geval moet u een gemeenschappelijke noemer vinden, die wordt weergegeven in de lijst
ps -ef
. Of neem na elknohup
-commando de PID op in een variabele (bij voorkeur een array) doorecho ${!}
en controleer op deze groep PIDs. Als ze allemaal verdwijnen, kun je doorgaan naar de tweedefor
lus
wait
ingebouwde.