Shell script espera comando de fondo

12

Estoy escribiendo un guión, pero hay algo que necesito y no puedo encontrar una manera de hacerlo ...

Necesito hacer un comando en segundo plano "command1 &" y luego en algún lugar del script necesito esperar a que termine antes de ejecutar command2. Básicamente, necesito esto:

NOTA: ¡cada comando se ejecuta en un directorio específico! al final del ciclo while, mi comando1 creó 4 directorios, donde en cada uno se ejecuta el proceso específico, por lo que el total del proceso en ejecución es 4

a=1

while [$a -lt 4 ]

     . command1
   #Generates 1 Process  

     a= `export $a +1`
done

   #Wait until the 4 process end and then run the command2 

    . command2

He visto algo sobre un waitcomando con el número de proceso pid, pero eso tampoco funcionó.

Joao Macau
fuente
¿Tu controlas command1? ¿Se puede modificar para que devuelva los PID de los 4 procesos?
terdon
¡Si! ya lo tengo :)
Joao Macau
He actualizado mi respuesta en consecuencia. Dime si coincide con tus expectativas.
Laurent C.
Esta Q está relacionada con esta: unix.stackexchange.com/questions/100801/… . La única diferencia es que necesita obtener el PID de un proceso en segundo plano. Puede usar la $!variable para obtener esto, pasándola al waitcomando como lo mostré allí. $!contiene el último PID en segundo plano, mientras que $$contiene el último PID de la ejecución del proceso.
slm
3
Bien, ahora tu guión no tiene ningún sentido. Hay errores de sintaxis y extrañeza por todas partes. ¿Podrías mostrarnos el guión real ? ¿Por qué estás buscando comandos? ¿Por qué no solo ejecutarlos?
terdon

Respuestas:

22

Puede usar el comando wait PIDpara esperar a que finalice un proceso.

También puede recuperar el PID del último comando con $!

En su caso, algo como esto funcionaría:

command1 & #run command1 in background
PID=$! #catch the last PID, here from command1
command2 #run command2 while command1 is running in background
wait $PID #wait for command1, in background, to end
command3 #execute once command1 ended

Después de su edición, ya que tiene varios PID y los conoce, puede hacer eso:

command1 & #run command1 in background
PID1=xxxxx
PID2=yyyyy
PID3=xxyyy
PID4=yyxxx
command2 #run command2 while command1 is running in background
wait $PID1 $PID2 $PID3 $PID4 #wait for the four processes of command1, in background, to end
command3 #execute once command1 ended
Laurent C.
fuente
Después de su edición, si conoce el PID creado (xxxxx, aaaa, xxyyy, yyxxx), también puede usar esperar, con la lista de PID para esperar (ver hombre). Si no los conoce, tal vez pueda reunirlos en command1 (¿qué es command1? ¿Un script propio?)
Laurent C.
Probablemente sea mejor asegurarse de que estén agrupados correctamente en primer lugar. Vea mi respuesta para tener una idea de cómo se podría hacer.
mikeserv
4

La forma más limpia de hacer esto sería que le comamnd1devolviera los PID de los procesos iniciados y los utilizara waiten cada uno de ellos, como sugiere la respuesta de @ LaurentC .

Otro enfoque sería algo como esto:

## Create a log file
logfile=$(mktemp)

## Run your command and have it print into the log file
## when it's finsihed.
command1 && echo 1 > $logfile &

## Wait for it. The [ ! -s $logfile ] is true while the file is 
## empty. The -s means "check that the file is NOT empty" so ! -s
## means the opposite, check that the file IS empty. So, since
## the command above will print into the file as soon as it's finished
## this loop will run as long as  the previous command si runnning.
while [ ! -s $logfile ]; do sleep 1; done

## continue
command2
terdon
fuente
lo siento pero aún no funciona .. ¡Mejoraré mi pregunta una vez más!
Joao Macau
0

Si utiliza el siguiente método, es posible que no necesite una "espera para todos los procesos" especial después del ciclo while. El ciclo esperará command1a que se complete la corriente antes de volver al principio. Tenga cuidado como con cualquier consejo. Tenga en cuenta que lo único que hice fue agregar & wait $!al final de su command1.

a=1
while [$a -lt 4 ]
     . command1  & wait $!
   #Generates 1 Process  
     a= `export $a +1`
done
Marius M
fuente