¿Cómo inicio un proceso en estado suspendido en Linux?

19

Prácticamente, necesito un proceso que se comporte, como si hubiera presionado Ctrl+Zjusto después de que comenzara.

Con suerte, es posible hacer tal cosa usando un script de shell.

(Además, conocer el PID resultante sería genial, por lo que podría continuar el proceso después).

java.is.for.desktop
fuente

Respuestas:

7

Después de comenzar un proceso, puede enviarlo SIGSTOP para suspenderlo. Para reanudarlo, envíe SIGCONT. Creo que este pequeño guión puede ayudarte

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

Ejecuta el proceso (comando enviado como parámetro), lo suspende, imprime la identificación del proceso y espera hasta que finalice.

radiante
fuente
1
Lo modifiqué para continuar al final: [enter] #!/bin/bash [enter] $@ & [enter] PID=$! [enter] kill -STOP $PID [enter] echo "Suspended: $PID, press ENTER to continue it" [enter] read [enter] kill -CONT $PID [enter] wait $PID [enter]echo
java.is.for.desktop
77
Para que lo sepas, el subproceso puede finalizar incluso antes de que puedas enviarle la señal de STOP.
MikeyB
16
Otro día en las carreras.
ctrl-alt-delor
23

¿Desde qué entorno está creando el proceso?

Si lo hace desde un entorno como el código C, puede bifurcar () y luego, en el elemento secundario, enviarse un SIGSTOP a usted mismo antes del exec (), evitando una mayor ejecución.

Una solución más genérica (probablemente la mejor) sería crear un trozo que lo haga. Entonces el programa stub:

  • Tomar argumentos que consisten en el nombre y los argumentos del programa real
  • enviar un SIGSTOP a sí mismo
  • exec () el programa real con argumentos apropiados

Esto asegurará que evite cualquier tipo de condiciones de carrera que tengan que ver con que el nuevo procesamiento llegue demasiado lejos antes de que pueda enviarle una señal.


Un ejemplo para shell:

#!/bin/bash
kill -STOP $$
exec "$@"

Y usando el codez anterior:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

El jobs -lmuestra el PID. Pero si lo está haciendo desde un shell, no necesita el PID directamente. Simplemente puede hacer: kill -CONT %1(suponiendo que solo tenga un trabajo).

¿Hacerlo con más de un trabajo? Dejado como ejercicio para el lector :)

MikeyB
fuente
Esperaba hacer esto desde un script de shell ...
java.is.for.desktop
Genial, así que como quieres hacer esto desde un script de shell, usa el programa stub.
MikeyB
20

La respuesta de MikeyB es correcta. De esta pregunta sobre superusuario, aquí hay una versión más concisa:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Para comprender esto, uno debe comprender cómo se inician los procesos en Unix: la execllamada del sistema reemplaza el programa que se está ejecutando actualmente por uno nuevo , preservando el PID existente. Entonces, la forma en que se crea un proceso independiente es primero fork, y luego exec, reemplazar el programa en ejecución en el proceso secundario con el programa deseado.

Los ingredientes de este comando de shell son:

  1. Los paréntesis (...)comienzan un sub-shell: otra instancia de BASH.
  2. El killcomando envía la señal STOP a este proceso, que lo pone en estado suspendido.
  3. Tan pronto como permita que el proceso continúe (enviándole la CONTseñal), el execcomando hace que se reemplace con el programa deseado. my_commandmantiene el PID original de la sub-shell.
  4. Puede usar la $!variable para obtener el PID del proceso.
nibot
fuente
2
Me gusta este, ya que es fundamentalmente correcto (solo que tuve que usarlo en -s STOPlugar de -SIGSTOP). Todavía me pregunto: ¿por qué tiene que ser en $BASHPIDlugar de $$? (Puede que realmente no entienda la diferencia).
Hibou57
1
Para $$vs $BASHPID, verifico que este último es el PID del sub-shell, mientras que no es el primero. Hay un problema curioso: al aplicar la sugerencia en un script bash, la mayoría de las veces falla, y tengo que hacer algo como esto: PID=$!; ps -p $PID; kill -s CONT $PID;... falla si elimino la ps -p $PIDparte: el proceso parece desaparecer (¿muerto?) Sin un mensaje de error en ningún lado . Está bien desde un shell interactivo, el problema es solo del script. Eso es demasiado misterioso.
Hibou57
Intenté usar esta solución para enumerar los descriptores de archivo de my_command. ( goo.gl/cNbUE8 ) pero los descriptores siguen siendo los mismos, no importa cuál es mi_comando.
rasty.g
Para ver las opciones de reemplazo $BASHPIDde proyectiles que no sean bash, consulte aquí
Jakob,