¿Puedo agregar de alguna manera un "&& prog2" a un prog1 que ya se está ejecutando?

87

La mayoría de los shells proporcionan funciones como &&y ;encadenar la ejecución de comandos de ciertas maneras. Pero, ¿qué pasa si un comando ya se está ejecutando? ¿Puedo agregar de alguna manera otro comando para que se ejecute dependiendo del resultado del primero?

Digamos que corrí

$ /bin/myprog
some output...

Pero realmente quería /bin/myprog && /usr/bin/mycleanup. No puedo matar myprogy reiniciar todo porque se perdería demasiado tiempo. Puedo Ctrl+ Zit y fg/ bgsi es necesario. ¿Esto me permite encadenar otro comando?

¡Estoy interesado principalmente en bash, pero las respuestas para todos los shells comunes son bienvenidas!

us2012
fuente

Respuestas:

118

Debería poder hacer esto en el mismo shell en el que se encuentra con el waitcomando:

$ sleep 30 &
[1] 17440

$ wait 17440 && echo hi

...30 seconds later...
[1]+  Done                    sleep 30
hi

extracto de la página de manual de Bash

wait [n ...]
     Wait for each specified process and return its termination status. Each n 
     may be a process ID or a job specification; if a job spec is given,  all 
     processes  in that job's pipeline are waited for.  If n is not given, all 
     currently active child processes are waited for, and the return status is 
     zero.  If n specifies a non-existent process or job, the return status is 
     127.  Otherwise, the return status is the exit status of the last process 
     or job waited for.
slm
fuente
Esperar el comando debería hacer el trabajo.
BillThor
Existen varios formularios cortos para ingresar el PID del proceso en segundo plano, como %, %1y $!. Es importante proporcionar el PID o el segundo comando siempre se ejecutará.
BillThor
@BillThor: ¿solo estás calificando la respuesta o diciéndome esto?
slm
Estoy calificando la respuesta. Un plano waitno proporcionará el resultado deseado. Es común usar las formas cortas, ya que son menos propensas a los errores tipográficos.
BillThor
2
Déjame ser el primero en felicitarte por tu nueva insignia brillante :)
terdon
63

fgvuelve con el código de salida del programa que reanuda. Por lo tanto, puede suspender su programa ^Zy luego usarlo fg && ...para reanudarlo.

$ /bin/myprog
some output...
^Z
[1]+ Stopped              /bin/myprog
$ fg && /usr/bin/mycleanup
John Kugelman
fuente
si vuelve a suspender antes de que termine y hace lo mismo con un comando diferente, ¿se reemplaza el encadenamiento inicial de mycleanup?
Burhan Ali
3
@BurhanAli La suspensión myprogpor segunda vez hace fgque finalice con el código de salida 20, que no es cero, por lo que el mycleanupcomando encadenado no se ejecuta.
n.st
1

No estoy seguro de si lo que está pidiendo es posible, pero si todavía tiene el shell desde el que inició el programa, siempre puede verificar $?el estado de salida del último proceso:

$ /bin/myprog
some output...
$ if [ $? -ne 0 ];then echo "non-zero exit status";else echo "0 exit status";fi
Joseph R.
fuente
1
Esto funcionará, pero luego tendrá que ejecutarlo manualmente, quiere ejecutarlo automáticamente cuando finalice el comando.
slm
@slm De acuerdo. No tengo una solución para ese problema exacto.
Joseph R.
3
Echa un vistazo al waitcomando en Bash.
slm
1

Si el trabajo está en primer plano, cualquiera de estos comandos tendría el mismo comportamiento que espera.

[ $? -eq 0 ] && prog2
(( $? )) || prog2

NOTA: $? contendrá el estado de retorno del programa en ejecución cuando salga.

Esto indica explícitamente qué haría el shell si hubiera ingresado originalmente el comando.

prog1 && prog2

Si el primer comando no está leyendo stdiny se está ejecutando en primer plano, se puede ingresar el nuevo comando mientras se ejecuta el primer comando. El shell lo leerá y ejecutará cuando se ejecute el primer comando. Si el comando se ejecutará en segundo plano, es poco probable que esté leyendo stdin.

EDITAR: WAITtambién se puede usar poner el trabajo en segundo plano y usar el comando. Esto debe hacerse con cuidado si otros trabajos también se han ejecutado en segundo plano. Se requiere una especificación de trabajo para que el WAITcomando devuelva el estado del trabajo esperado.

BillThor
fuente
Esto funcionará, pero luego tendrá que ejecutarlo manualmente, quiere ejecutarlo automáticamente cuando finalice el comando.
slm
44
@slm Mientras el comando no lea stdin, se puede ingresar el nuevo comando mientras se ejecuta el primer comando. El shell lo leerá tan pronto como se complete el primer comando.
BillThor
Si hace algo en el caparazón después de que haya sido puesto en segundo plano, es probable que se manguere. Al menos según los prelim. ¡Pruebas que he estado haciendo hasta ahora!
slm
2
@BillThor Creo que deberías agregar ese comentario a tu respuesta.
Joseph R.
2
Sí, usar waittampoco es ideal. La ventaja, en mi opinión, es que nos da una API más clara con la que estamos tratando. Escribir más comandos en la línea de comando después de que algo se está ejecutando me pareció un poco raro. waittodavía sufre de no obtener un enlace directo al PID en ejecución, wrt el estado de retorno. Sin embargo, esto parece ser un problema más con la forma en que Bash implementa las cosas: stackoverflow.com/questions/356100/… . Entonces esto podría ser tan bueno como sea posible.
slm