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
nohupes evitar que una salida remota de shell elimine sus procesos de trabajo, debe usarnohupen el script en sí, no en los procesos de trabajo individuales que crea. -
Como se explica aquí ,
nohupsolo 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, unwaitsimple entre los dosforbucles provocará el segundoforpara ejecutarse solo después de que todos los procesos secundarios iniciados por el primerforhayan salido. -
Con un
wait:se esperan todos los procesos secundarios actualmente activos y el estado de retorno es cero.
-
Si necesita ejecutar el segundo
forsolo 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
Rocc1plusen eltopcomando - 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.
-
waithace quebashespere los trabajos en segundo plano que generó, nada más. Puede haber algo de confusión aquí: estosforbucles, ¿los guardó en un archivo y los invocó como un script (lo que asumí, debido al##scriptlínea), o los está escribiendo a mano en la terminal? - Estaba haciendo
cat file.txt | whiley los pids no se establecieron fuera del bucle por lo que el comando de espera vio una cadena$pidsvacía. por qué sucede esto se explica en serverfault.com/q/259339 . se corrige fácilmente comowhile ... < files.txtcomo 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
topmuestraRa 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 segundoforbucle
waitincorporado.