![¿Cómo ejecutar un comando después de que finaliza uno existente que ya se está ejecutando?](https://rvso.com/image/1289035/%C2%BFC%C3%B3mo%20ejecutar%20un%20comando%20despu%C3%A9s%20de%20que%20finaliza%20uno%20existente%20que%20ya%20se%20est%C3%A1%20ejecutando%3F.png)
Si comienzo un guión que va a llevar mucho tiempo, inevitablemente me doy cuenta después de haberlo iniciado y desearía tener una forma de generar algún tipo de alerta una vez que termine.
Entonces, por ejemplo, si ejecuto:
really_long_script.sh
y presione enter... ¿cómo puedo ejecutar otro comando una vez que finalice?
Respuesta1
Puede separar varios comandos por ;
, para que se ejecuten secuencialmente, por ejemplo:
really_long_script.sh ; echo Finished
Si desea ejecutar el siguiente programa solo si el script finalizó con el código de retorno 0 (lo que generalmente significa que se ejecutó correctamente), entonces:
really_long_script.sh && echo OK
Si desea lo contrario (es decir, continuar sólo si el comando actual ha fallado), entonces:
really_long_script.sh || echo FAILED
Puede ejecutar su secuencia de comandos en segundo plano (pero tenga cuidado, la salida de las secuencias de comandos ( stdout
y stderr
) continuará yendo a su terminal a menos que la redirija a alguna parte), y luego wait
:
really_long_script.sh &
dosomethingelse
wait; echo Finished
Si ya ejecutó el script, puede suspenderlo con Ctrl-Z
y luego ejecutar algo como:
fg ; echo Finished
Donde fg
pone el proceso suspendido en primer plano ( bg
lo haría ejecutarse en segundo plano, más o menos como empezó con &
)
Respuesta2
Si el proceso no se ejecuta en el tty actual, intente esto:
watch -g ps -opid -p <pid>; mycommand
Respuesta3
También puedes usar el control de trabajo de bash. si empezaste
$ really_long_script.sh
luego presione ctrl+z para suspenderlo:
^Z
[1]+ Stopped really_long_script.sh
$ bg
para reiniciar el trabajo en segundo plano (como si lo hubiera iniciado con really_long_script.sh &
). Entonces puedes esperar este trabajo en segundo plano con
$ wait N && echo "Successfully completed"
donde N es el ID del trabajo (probablemente 1 si no ejecutó ningún otro trabajo en segundo plano) que también se muestra como se muestra [1]
arriba.
Respuesta4
Hace un tiempo escribí un script para esperar el final de otro proceso. NOISE_CMD
podría ser algo así notify-send ...
, dado que DISPLAY
está configurado correctamente.
#!/bin/bash
NOISE_CMD="/usr/bin/mplayer -really-quiet $HOME/sfx/alarm-clock.mp3"
function usage() {
echo "Usage: $(basename "$0") [ PROCESS_NAME [ PGREP_ARGS... ] ]"
echo "Helpful arguments to pgrep are: -f -n -o -x"
}
if [ "$#" -gt 0 ] ; then
PATTERN="$1"
shift
PIDS="$(pgrep "$PATTERN" "$@")"
if [ -z "$PIDS" ] ; then
echo "No process matching pattern \"$PATTERN\" found."
exit
fi
echo "Waiting for:"
pgrep -l "$PATTERN" "$@"
for PID in $PIDS ; do
while [ -d "/proc/$PID" ] ; do
sleep 1
done
done
fi
exec $NOISE_CMD
Sin ningún argumento, simplemente haz algo de ruido inmediatamente. Este comportamiento permite algo como esto por conveniencia (digamos que llama al script a continuación alarm.sh
):
apt-get upgrade ; ~/bin/alarm.sh
Por supuesto, puedes hacer muchas cosas divertidas con un script de este tipo, como dejar que una instancia de alarm.sh
espere a una instancia de alarm.sh
, que está esperando algún otro comando. O ejecutar un comando justo después de que alguna tarea de otro usuario que haya iniciado sesión haya finalizado... >:D
Una versión anterior del script anterior podría ser interesante si desea evitar una dependencia pgrep
y aceptar buscar los ID de los procesos usted mismo:
#!/bin/bash
if [ "$#" -lt 2 -o ! -d "/proc/$1" ] ; then
echo "Usage: $(basename "$0") PID COMMAND [ ARGUMENTS... ]"
exit
fi
while [ -d "/proc/$1" ] ; do
sleep 1
done
shift
exec "$@"
Ligeramente fuera de tema, pero útil en situaciones similares: a uno le podría interesarreptyr
, una herramienta que "roba" un proceso de algún shell (principal) y lo ejecuta desde el shell actual. He probado implementaciones similares y reptyr
es la más bonita y confiable para mis propósitos.