Como inicio um processo no estado suspenso no Linux?

19

Na prática, preciso de um processo que se comporte, como se eu tivesse pressionado Ctrl+Zlogo após o início.

Felizmente, é possível fazer isso usando um script de shell.

(Além disso, saber o PID resultante seria ótimo, para que eu pudesse continuar o processo posteriormente.)

java.is.for.desktop
fonte

Respostas:

7

Depois de iniciar um processo, você pode enviar o SIGSTOP para suspendê-lo. Para retomar, envie SIGCONT. Eu acho que esse pequeno script pode ajudá-lo

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

Executa o processo (comando send como parâmetro), suspende-o, imprime o ID do processo e aguarda até que ele termine.

radiante
fonte
1
I modificado para continuar no final: [entrar] #!/bin/bash [entrar] $@ & [entrar] PID=$! [entrar] kill -STOP $PID [entrar] echo "Suspended: $PID, press ENTER to continue it" [entrar] read [entrar] kill -CONT $PID [entrar] wait $PID [entrar]echo
java.is.for.desktop
7
Só para você saber, o subprocesso pode terminar antes mesmo de você ter a chance de enviar o sinal STOP para ele.
25811 MikeyB
16
Outro dia nas corridas.
ctrl-alt-Delor
23

Em qual ambiente você está criando o processo?

Se você estiver fazendo isso em um ambiente como o código C, poderá bifurcar () e, em seguida, no filho, enviar um SIGSTOP para si mesmo antes do exec (), impedindo a execução adicional.

Uma solução mais genérica (provavelmente a melhor) seria criar um esboço que faça isso. Portanto, o programa stub:

  • Aceitar argumentos que consistem no nome e argumentos do programa real
  • envie um SIGSTOP para si mesmo
  • exec () o programa real com argumentos apropriados

Isso garantirá que você evite qualquer tipo de condição de corrida relacionada ao novo processamento, indo muito longe antes que você possa enviar um sinal para ele.


Um exemplo para shell:

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

E usando codez acima:

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

O jobs -lmostra o PID. Mas se você estiver fazendo isso a partir de um shell, não precisará do PID diretamente. Você pode apenas fazer: kill -CONT %1(supondo que você tenha apenas um emprego).

Fazendo isso com mais de um trabalho? Deixado como um exercício para o leitor :)

MikeyB
fonte
Eu estava esperando para fazer isso a partir de um shell script ...
java.is.for.desktop
Ótimo, então, como você deseja fazer isso a partir de um script shell, use o programa stub.
25611 MikeyB
20

A resposta de MikeyB está correta. A partir desta pergunta sobre superusuário, aqui está uma versão mais concisa:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Para entender isso, é preciso entender como os processos são iniciados no unix: a execchamada do sistema substitui o programa atualmente em execução por um novo , preservando o PID existente. Portanto, a maneira como um processo independente é criado é primeiro forke exec, em seguida , substituindo o programa em execução no processo filho pelo programa desejado.

Os ingredientes deste comando shell são:

  1. Os parênteses (...)iniciam uma subcasca: outra instância do BASH.
  2. O killcomando envia o sinal STOP para esse processo, que o coloca no estado suspenso.
  3. Assim que você permitir que o processo continue (enviando o CONTsinal), o execcomando fará com que ele se substitua pelo programa desejado. my_commandmantém o PID original do sub-shell.
  4. Você pode usar a $!variável para obter o PID do processo.
nibot
fonte
2
Eu gosto deste, pois é fundamentalmente correto (só que eu tive que usar em -s STOPvez de -SIGSTOP). Ainda me pergunto: por que tem que ser em $BASHPIDvez de $$? (Eu posso realmente não entender a diferença).
Hibou57
1
Para $$vs $BASHPID, verifico que o último é o PID do sub-shell, enquanto não o primeiro. Há um problema engraçado: a aplicação da dica em um script bash geralmente falha e eu tenho que fazer algo assim: PID=$!; ps -p $PID; kill -s CONT $PID;… falha se eu remover a ps -p $PIDparte: o processo parece desaparecer (morto?) Sem uma mensagem de erro em qualquer lugar . Não há problema em um shell interativo, o problema é apenas do script. Isso é muito misterioso.
Hibou57
Eu tentei usar esta solução para listar descritores de arquivo de my_command. ( goo.gl/cNbUE8 ), mas os descritores ainda são os mesmos, não importa o que seja meu comando.
rasty.g
Para opções de substituição $BASHPIDde conchas que não sejam o bash, consulte aqui
Jakob