Tengo un script bash que se parece a lo siguiente:
##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
Me gustaría crear otro bucle for después del primero para continuar por otros 30. Por ejemplo
##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
Me gustaría finalice el primer conjunto de trabajos antes de iniciar el nuevo conjunto. Pero debido al nohup
parece que todos se ejecutan simultáneamente.
Tengo nohup
porque me conecto de forma remota a mi servidor e inicio los trabajos allí y luego cierro mi bash. ¿Existe una solución alternativa?
Comentarios
Responder
Deberá utilizar el comando wait
para Haga esto por usted. Puede capturar todos los ID de procesos secundarios y esperarlos específicamente, o si son los únicos procesos en segundo plano que está creando su secuencia de comandos, puede simplemente llamar a wait
sin un argumento. Por ejemplo:
#!/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"
Respuesta
Algunos puntos:
-
Si su objetivo con
nohup
es evitar que una salida remota de shell elimine sus procesos de trabajo, debe usarnohup
en el script en sí, no en los procesos de trabajo individuales que crea. -
Como se explica aquí ,
nohup
solo evita que los procesos reciban SIGHUP y de interactuar con el terminal, pero no rompe la relación entre el shell y sus procesos secundarios. -
Debido al punto anterior, con o sin
nohup
, unwait
simple entre los dosfor
bucles provocará el segundofor
para ejecutarse solo después de que todos los procesos secundarios iniciados por el primerfor
hayan salido. -
Con un
wait
:se esperan todos los procesos secundarios actualmente activos y el estado de retorno es cero.
-
Si necesita ejecutar el segundo
for
solo si no hubo errores en el primero , luego deberá guardar cada PID de trabajador con$!
y pasarlos todos await
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Comentarios
- Hay pu Serían otros trabajos ejecutándose en el servidor. Así que ' solo quiero esperar mi lote … son scripts R, por lo que se ejecutan bajo
R
occ1plus
en eltop
comando - También ' me gustaría usar nohup dentro para ejecutar todos los comandos en " paralelo ". básicamente se trata de simulaciones para un programa científico. Quiero ejecutar 180 simulaciones en total, pero en lotes de 60. El contador también debe ir de 1 a 180. Si las hago una a la vez, tomará demasiado tiempo.
-
wait
hace quebash
espere los trabajos en segundo plano que generó, nada más. Puede haber algo de confusión aquí: estosfor
bucles, ¿los guardó en un archivo y los invocó como un script (lo que asumí, debido al##script
línea), o los está escribiendo a mano en la terminal? - Estaba haciendo
cat file.txt | while
y los pids no se establecieron fuera del bucle por lo que el comando de espera vio una cadena$pids
vacía. por qué sucede esto se explica en serverfault.com/q/259339 . se corrige fácilmente comowhile ... < files.txt
como se responde en serverfault.com/a/259346 - Solo por curiosidad ¿Cuál es el propósito del signo + con la variable pids?
Responder
Use el fg
incorporado. Espera hasta que finalicen los procesos en segundo plano.
Intente help fg
para obtener más detalles.
Comentarios
- Un script se ejecuta sin control de trabajo.
Responder
Si inserta algo como el siguiente segmento de código entre los dos bucles for
, podría ayudar.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Por supuesto, si su aplicación Rscript
tiene la posibilidad de no completarse correctamente y demorarse, es posible que su segundo bucle for no tenga la oportunidad de ejecutarse. El segmento de código anterior asume que todos los procesos con el identificador Rscript --vanilla
se completarán y desaparecerán correctamente. Sin saber qué hace su aplicación y cómo se ejecuta, tengo que confiar en esta suposición.
EDIT
A la luz de los comentarios, esto encajaría mejor tus necesidades. (incluye su código original y la lógica de verificación de finalización)
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
Comentarios
- El proceso El nombre en
top
muestraR
a veces occ1plus
. - En ese caso, necesitará encontrar un denominador común, que aparezca en la lista
ps -ef
. O después de cada comandonohup
, registre el PID en una variable (preferiblemente una matriz) porecho ${!}
y verifique este grupo de PID. Cuando desaparezcan todos, puede continuar con el segundofor
bucle
wait
incorporado.