En un script de shell, ¿cómo puedo (1) iniciar un comando en segundo plano (2) esperar x segundos (3) ejecutar un segundo comando mientras se ejecuta ese comando?

11

Esto es lo que necesito que suceda:

  1. iniciar el proceso A en segundo plano
  2. espera x segundos
  3. iniciar el proceso B en primer plano

¿Cómo puedo hacer que la espera suceda?

Estoy viendo que 'dormir' parece detener todo y en realidad no quiero 'esperar' a que el proceso A termine por completo. He visto algunos bucles basados ​​en el tiempo, pero me pregunto si hay algo más limpio.

Julie
fuente
44
Le sugiero que mejore esta pregunta proporcionando un ejemplo simple de lo que ya ha intentado.
Andy Dalton
10
¿De dónde sacas la impresión que sleepdetiene el proceso A? ¿Puede mostrar el proceso de prueba que está utilizando o una salida indicativa de esto? Si el proceso A se detiene, es más probable que esté tratando de leer desde el terminal mientras se ejecuta en segundo plano y se detiene por esa razón, en lugar de cualquier cosa relacionada sleep.
Charles Duffy
3
... si ese es el caso, process_a </dev/null &adjuntará su stdin en /dev/nulllugar del TTY, y eso puede ser suficiente para evitar el problema.
Charles Duffy
Desde mi experiencia, el sueño solo bloqueará el proceso actual y, por lo tanto, no el proceso iniciado previamente en segundo plano con &
MADforFUNandHappy el

Respuestas:

28

A menos que esté malinterpretando su pregunta, simplemente se puede lograr con este breve script:

#!/bin/bash

process_a &
sleep x
process_b

(y agregue un extra waital final si desea que su script espere a process_aque termine antes de salir).

Incluso puede hacer esto como una línea, sin la necesidad de un script (como lo sugiere @BaardKopperud):

process_a & sleep x ; process_b
Dr_
fuente
66
Tenga en cuenta que no necesita basheso, cualquier shell lo hará, incluido el de su sistema sh, por lo que no necesita agregar una dependencia de bash para su script.
Stéphane Chazelas
44
O simplemente: process_a & sleep x; process_b
Baard Kopperud
9

Puede usar el operador de control de fondo (&) para ejecutar un proceso en segundo plano y el sleepcomando esperar antes de ejecutar un segundo proceso, es decir:

#!/usr/bin/env bash
# script.sh

command1 &
sleep x
command2

Aquí hay un ejemplo de dos comandos que imprimen algunos mensajes con marca de tiempo:

#!/usr/bin/env bash

# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
    echo "$(date) - I am running in the background";
    sleep 1;
done &> background-process-output.txt &

# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5 

# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
    echo "$(date) - I am running in the foreground";
    sleep 1;
done

Ejecútelo para verificar que exhibe el comportamiento deseado:

user@host:~$ bash script.sh

Fri Dec  1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec  1 13:41:10 CST 2017 - Sleeping...
Fri Dec  1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec  1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:20 CST 2017 - I am running in the foreground
...
...
...
igal
fuente
2
La pregunta pide "iniciar el proceso B en primer plano ".
Sparhawk
1
@Sparhawk Wow. Totalmente mal interpretado eso, no hay explicación. Gracias por el aviso - código corregido. Grave nostalgia de su nombre de usuario, por cierto.
Igual
1
¡Sin preocupaciones! (¡También el nombre de usuario era originalmente una referencia a este tipo , pero solo más tarde me di cuenta de que era un personaje de Eddings! Y me dan ganas de volver a leer esos libros ...)
Sparhawk
5

Me gusta la respuesta de @ dr01, pero él no verifica el código de salida, por lo que no sabe si tuvo éxito o no.

Aquí hay una solución que verifica los códigos de salida.

#!/bin/bash

# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0

# check the exitcode for process A
wait $PID1    
if (($? != 0)); then
    echo "ERROR: process_a exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi

# check the exitcode for process B
wait $PID2
if (($? != 0)); then
    echo "ERROR: process_b exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi
exit ${exitcode}

Por lo general, almaceno los PID en una matriz bash y luego la comprobación de pid es un bucle for.

Trevor Boyd Smith
fuente
2
Es posible que desee reflejar esos códigos de salida en el estado de salida de su script, comoA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas, el
1
@ StéphaneChazelas buena idea. Actualicé el código para asegurarme de que se devuelve un código de salida distinto de cero si uno o ambos fallan.
Trevor Boyd Smith
El OP quiere process_bcorrer en primer plano. Presumiblemente process_apodría salir mientras se process_bestá ejecutando, pero aún puede waithacerlo y obtener el estado de salida después de haber recopilado el estado de salida del primer plano de process_bla manera normal, $?directamente.
Peter Cordes