pausar un script bash hasta que los comandos anteriores hayan terminado

20

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 durante 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 que el primer conjunto de trabajos finalice antes de comenzar el nuevo conjunto. Pero debido a nohupesto, parece que todos se ejecutan simultáneamente.

Lo hice nohupporque me conecto de forma remota a mi servidor e inicio los trabajos allí y luego cierro mi bash. ¿Hay una solución alternativa?

Masfenix
fuente
1
Busque el manual para el waitincorporado.
Satō Katsura

Respuestas:

22

Querrá usar el waitcomando para hacer 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 script, simplemente puede llamar waitsin 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"
ParanoidGeek
fuente
6

Algunos puntos:

  • Si su objetivo nohupes evitar que una salida de shell remota mate sus procesos de trabajo, debe usar nohupel script en sí, no los procesos de trabajo individuales que crea.

  • Como se explica aquí , nohupsolo evita que los procesos reciban SIGHUP e interactúen con el terminal, pero no interrumpe la relación entre el shell y sus procesos secundarios.

  • Debido al punto anterior, con o sin nohup, un simple waitentre los dos forbucles hará que el segundo forse ejecute solo después de que todos los procesos secundarios iniciados por el primero forhayan salido.

  • Con un simple 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, deberá guardar cada PID de trabajador $!y pasarlos a wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }
Matei David
fuente
Podría haber otros trabajos ejecutándose en el servidor. Entonces, solo quiero esperar mi lote ... son scripts R, por lo que se ejecutan bajo Ro cc1plusen el topcomando
masfenix
También me gustaría usar nohup en el interior 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.
masfenix
waithace bashque espere los trabajos en segundo plano que generó, nada más. Puede haber alguna confusión aquí: estos forbucles, ¿los guardó en un archivo e invocó como un script (lo que asumí, debido a la ##scriptlínea), o los está escribiendo a mano en el terminal?
Matei David
-1

Usa el fgincorporado. Espera hasta que finalicen los procesos en segundo plano.

Prueba help fgpara más detalles.

Luchostein
fuente
Se ejecuta un script sin control de trabajo.
Kusalananda
-1

Si inserta algo como el siguiente segmento de código entre sus dos forbucles, 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 Rscripttiene la posibilidad de no completarse con éxito y demorarse, es posible que su segundo ciclo for no tenga la oportunidad de ejecutarse. El segmento de código anterior supone que todos los procesos con el identificador Rscript --vanillase 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.

EDITAR

A la luz de los comentarios, esto se adaptaría mejor a sus necesidades. (incluye su código original, así como 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
MelBurslan
fuente
El nombre del proceso en topmuestra a Rveces o cc1plus.
masfenix
En ese caso, necesitará encontrar un denominador común, que aparece en la ps -eflista. O después de cada nohupcomando, registre el PID en una variable (preferiblemente una matriz) echo ${!}y compruebe este grupo de PID. Cuando todos desaparezcan, puede continuar con el segundo forciclo
MelBurslan