Jai un script bash qui ressemble à ce qui suit:
##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
Je voudrais créer une autre boucle for après la première pour continuer pendant 30. Par exemple
##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
Je voudrais le premier ensemble de travaux à terminer avant de démarrer le nouvel ensemble. Mais à cause des nohup
, il semble quils soient tous exécutés simultanément.
Jai nohup
parce que je me connecte à distance à mon serveur et démarre les travaux là-bas, puis ferme mon bash. Existe-t-il une solution alternative?
Commentaires
Réponse
Vous « voudrez utiliser la commande wait
pour faites-le pour vous. Vous pouvez soit capturer tous les ID de processus enfants et les attendre spécifiquement, soit sil sagit des seuls processus darrière-plan que votre script crée, vous pouvez simplement appeler wait
sans argument. Par exemple:
#!/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éponse
Quelques points:
-
Si votre objectif avec
nohup
est dempêcher une sortie shell distante de tuer vos processus de travail, vous devez utilisernohup
sur le script lui-même, pas sur les processus de travail individuels quil crée. -
Comme expliqué ici ,
nohup
empêche uniquement les processus de recevoir SIGHUP et dinteragir avec le terminal, mais cela ne rompt pas la relation entre le shell et ses processus enfants. -
À cause du point ci-dessus, avec ou sans
nohup
, un simplewait
entre les deuxfor
boucles provoquera la deuxièmefor
à exécuter uniquement après la fermeture de tous les processus enfants lancés par le premierfor
. -
Avec un simple
wait
:tous les processus enfants actuellement actifs sont attendus et le statut de retour est zéro.
-
Si vous devez exécuter le deuxième
for
uniquement sil ny a pas eu derreur dans le premier , alors vous « devrez enregistrer chaque PID worker avec$!
, et les transmettre tous àwait
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Commentaires
- Il y a cou ld être dautres travaux en cours dexécution sur le serveur. Donc je ' ne veux attendre que mon lot .. ce sont des scripts R donc ils sont exécutés sous
R
oucc1plus
dans la commandetop
- Aussi ' jaimerais utiliser nohup à lintérieur pour exécuter toutes les commandes en " parallel ". ce sont essentiellement des simulations pour un programme scientifique. Je souhaite exécuter 180 simulations au total, mais par lots de 60. Le compteur doit également passer de 1 à 180. Si je les fais une à la fois, cela prendra trop de temps.
-
wait
fait quebash
attend les travaux darrière-plan quil a générés, rien dautre. Il pourrait y avoir une certaine confusion ici – ces bouclesfor
, les avez-vous sauvegardées dans un fichier et les avez-vous appelées en tant que script (ce que jai supposé, à cause du##script
), ou les saisissez-vous à la main dans le terminal? - Jétais en train de faire
cat file.txt | while
et les pids nétaient pas définis en dehors de la boucle la commande wait a donc vu une chaîne$pids
vide. pourquoi cela se produit est expliqué à serverfault.com/q/259339 . facilement corrigé commewhile ... < files.txt
comme répondu à serverfault.com/a/259346 - Juste curieux à quoi sert le signe + avec la variable pids?
Réponse
Utilisez le fg
intégré. Il attend la fin des processus darrière-plan.
Essayez help fg
pour plus de détails.
Commentaires
- Un script sexécute sans contrôle de tâche.
Réponse
Si vous insérez quelque chose comme le segment de code suivant entre vos deux boucles for
, cela peut aider.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Bien sûr, si votre application Rscript
a une chance de ne pas réussir et de persister, votre deuxième boucle for peut ne pas avoir une chance de sexécuter. Le segment de code ci-dessus suppose que tous les processus avec lidentificateur Rscript --vanilla
se termineront et disparaîtront correctement. Sans savoir ce que fait votre application et comment elle fonctionne, je dois me fier à cette hypothèse.
EDIT
À la lumière des commentaires, cela conviendrait mieux vos besoins. (il inclut votre code dorigine ainsi que la logique de vérification dachèvement)
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
Commentaires
- Le processus nom dans
top
affiche parfoisR
oucc1plus
. - Dans ce cas, vous devrez trouver un dénominateur commun, apparaissant dans la liste
ps -ef
. Ou après chaque commandenohup
, enregistrez le PID dans une variable (de préférence un tableau) parecho ${!}
et vérifiez ce groupe de PID. Lorsquils disparaissent tous, vous pouvez passer à la deuxièmefor
boucle
wait
intégré.