Come posso avviare un processo in stato sospeso sotto Linux?


19

Praticamente, ho bisogno di un processo che si comporti, come se avessi premuto Ctrl+Zsubito dopo l'avvio.

Speriamo che sia possibile fare una cosa del genere usando uno script di shell.

(Inoltre, conoscere il PID risultante sarebbe fantastico, quindi potrei continuare il processo in seguito.)

Risposte:


7

Dopo aver avviato un processo, è possibile inviarlo a SIGSTOP per sospenderlo. Per riprenderlo, invia SIGCONT. Penso che questo piccolo copione possa aiutarti

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

Esegue il processo (comando invia come parametro), lo sospende, stampa l'id del processo e attende fino alla fine.


1
Ho modificato per continuare alla fine: [Invio] #!/bin/bash [Invio] $@ & [Invio] PID=$! [Invio] kill -STOP $PID [Invio] echo "Suspended: $PID, press ENTER to continue it" [Invio] read [Invio] kill -CONT $PID [Invio] wait $PID [Invio]echo
java.is.for.desktop

7
Proprio per questo sai, il sottoprocesso potrebbe terminare prima ancora che tu abbia la possibilità di inviargli il segnale di STOP.
MikeyB,

16
Un altro giorno alle gare.
ctrl-alt-delor,

23

Da quale ambiente stai creando il processo?

Se lo stai facendo da un ambiente come il codice C, puoi fork () e poi nel figlio, inviare un SIGSTOP a te stesso prima di exec (), impedendo ulteriori esecuzioni.

Una soluzione più generica (probabilmente la migliore) sarebbe quella di creare uno stub che lo faccia. Quindi il programma stub dovrebbe:

  • Prendi argomenti costituiti dal nome e dagli argomenti del programma reale
  • invia un SIGSTOP a se stesso
  • exec () il vero programma con argomenti appropriati

Ciò assicurerà di evitare che qualsiasi condizione di gara legata alla nuova elaborazione si spinga troppo in là prima di poter inviare un segnale.


Un esempio per la shell:

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

E usando codez sopra:

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:~$ 

La jobs -lmostra il PID. Ma se lo fai da una shell non hai bisogno direttamente del PID. Puoi semplicemente fare: kill -CONT %1(supponendo che tu abbia un solo lavoro).

Lo fai con più di un lavoro? Lasciato come esercizio per il lettore :)


Speravo di farlo da uno script di shell ...
java.is.for.desktop

Fantastico, quindi poiché vuoi farlo da uno script di shell, usa il programma stub.
MikeyB,

20

La risposta di MikeyB è corretta. Da questa domanda su superutente, ecco una versione più concisa:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Per capirlo, è necessario capire come vengono avviati i processi su unix: la execchiamata di sistema sostituisce il programma attualmente in esecuzione con uno nuovo , preservando il PID esistente. Quindi il modo in cui viene creato un processo indipendente è prima di tutto fork, quindi exec, sostituire il programma in esecuzione nel processo figlio con il programma desiderato.

Gli ingredienti di questo comando shell sono:

  1. Le parentesi (...)iniziano una sotto-shell: un'altra istanza di BASH.
  2. Il killcomando invia il segnale STOP a questo processo, che lo mette in stato sospeso.
  3. Non appena si consente al processo di continuare (inviandolo il CONTsegnale), il execcomando lo fa sostituire con il programma desiderato. my_commandmantiene il PID originale della sotto-shell.
  4. È possibile utilizzare la $!variabile per ottenere il PID del processo.

2
Mi piace questo, poiché è fondamentalmente corretto (solo che ho dovuto usare al -s STOPposto di -SIGSTOP). Mi chiedo ancora: perché deve essere $BASHPIDinvece di $$? (Potrei davvero non capire la differenza).
Hibou57,

1
Per $$vs $BASHPID, controllo che quest'ultimo sia il PID della sotto-shell, mentre non il primo. C'è un problema divertente: l'applicazione del suggerimento in uno script bash, il più delle volte fallisce, e devo fare qualcosa del genere: PID=$!; ps -p $PID; kill -s CONT $PID;... fallisce se rimuovo la ps -p $PIDparte: il processo sembra scomparire (ucciso?) Senza un messaggio di errore ovunque . Va bene da una shell interattiva, il problema è solo dallo script. È troppo misterioso.
Hibou57,

Ho provato a utilizzare questa soluzione per elencare i descrittori di file di my_command. ( goo.gl/cNbUE8 ) ma i descrittori sono sempre gli stessi no mather cos'è my_command.
rasty.g

Per le opzioni di sostituzione $BASHPIDper shell diverse da bash, vedere qui
Jakob
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.