Ejecute un comando bash cuando finalice un proceso

Ejecute un comando bash cuando finalice un proceso

Tengo dos scripts que usan GPU y entrenan modelos de ML. Quiero empezar a usarlos antes de irme a dormir para que funcionen por la noche y espero ver algunos resultados por la mañana.

Pero debido a que la memoria de la GPU es limitada, quiero ejecutarlos en serie en lugar de en paralelo.

Puedo hacerlo con python train_v1.py && python train_v2.py; pero digamos que comencé a entrenar el train_v1. Mientras tanto, debido a que la capacitación lleva mucho tiempo, comencé y terminé la implementación del segundo script train_v2.pyy quiero ejecutarlo automáticamente cuando python train_v1.pyesté terminado.

¿Cómo puedo lograr eso? Gracias.

Respuesta1

Este es un enfoque que no implica realizar bucles y verificar si el otro proceso todavía está activo, o llamar train_v1.pyde una manera diferente a la que haría normalmente:

$ python train_v1.py
^Z
[1]+  Stopped                 python train_v1.py
$ % && python train_v2.py

Soy ^Zyo presionando Ctrl+ Zmientras el proceso se ejecuta para dormir train_v1.pyenviándole una SIGTSTPseñal. Luego, le digo al shell que lo active con %, usándolo como un comando al que puedo agregar && python train_v2.pyal final. Esto hace que se comporte tal como si lo hubieras hecho python train_v1.py && python train_v2.pydesde el principio.

En lugar de %, también puedes usar fg. Es lo mismo. Si desea obtener más información sobre este tipo de características del shell, puede leer sobre ellas enla sección "CONTROL DE TRABAJO" de la página de manual de bash.

EDITAR: Cómo seguir agregando a la cola

Como señaló jamesdlin en un comentario, si intenta continuar con el patrón para agregarlo, train_v3.pypor ejemplo, antes de que comience la versión 2, encontrará que no puede:

$ % && python train_v2.py
^Z
[1]+  Stopped                 python train_v1.py

Sólo train_v1.pyse detiene porque train_v2.pyno ha comenzado, y no se puede detener/suspender/dormir algo que ni siquiera ha comenzado.

$ % && python train_v3.py

resultaría en lo mismo que

python train_v1.py && python train_v3.py

porque %corresponde al último proceso suspendido. En lugar de intentar agregar v3algo así, uno debería usar el historial:

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py

Se puede hacer una expansión del historial como se muestra arriba, o recuperar el último comando con una combinación de teclas (como arriba) y agregar v3 al final.

$ % && python train_v2.py && python train_v3.py

Eso es algo que se puede repetir para agregar más al proyecto.

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
^Z
[1]+  Stopped                 python train_v1.py
$ !! && python train_v4.py
% && python train_v2.py && python train_v3.py && python train_v4.py

Respuesta2

Si ya ha comenzado python train_v1.py, posiblemente podría utilizar pgreppara sondear ese proceso hasta que desaparezca y luego ejecutar su segundo script de Python:

while pgrep -u "$USER" -fx 'python train_v1.py' >/dev/null
do
    # sleep for a minute
    sleep 60
done
python train_v2.py

Al usar -fy -xusted compara la línea de comando exacta que se usó para iniciar el primer script de Python. En algunos sistemas, pgrepimplementa una -qopción que lo hace silencioso (al igual que ), lo que significa que no sería necesaria grep -qla redirección a ./dev/null

La -uopción restringe la coincidencia a los comandos que estás ejecutando (y no a un amigo u otra persona en el mismo sistema).

Si aún no has iniciado el primer script:

Como se mencionó en los comentarios, puede iniciar el segundo script inmediatamente después del primero. El hecho de que el segundo script no exista, o que aún no esté listo para ejecutarse, no importa (siempre que esté listo para ejecutarse cuando finalice el primer script):

python train_v1.py; python train_v2.py

Al hacerlo de esta manera, se iniciará el segundo script independientemente del estado de salida del primer script. Usar &&en lugar de ;, como muestra en la pregunta, también funcionará, pero requerirá que el primer script finalice correctamente para que se inicie el segundo script.

Respuesta3

Puede iniciar el primer script con

python train_v1.py; touch finished

Luego simplemente haga un bucle que verifique periódicamente si finishedexiste:

while [ ! -f finished ] ; do     
    sleep 5
done
python train_v2.py
rm finished

Respuesta4

Si no necesita saber el estado de salida del primer script, le recomiendo algo comolo que escribió Kusalananda.

Si necesita conocer el estado de salida (lo cual probablemente no sea necesario en este caso, pero puede que alguien más venga buscando una solución que lo haga), es más complicado. he escrito unpequeña utilidad de Linuxpwaitque le permite esperar a que finalice un proceso y conocer su estado de salida.

información relacionada