Inicie um processo em segundo plano a partir de um script e gerencie-o quando o script terminar

15

Eu gostaria de executar e configurar um processo de maneira semelhante a um daemon a partir de um script.
Meu shell é zsh emulado no Cygwin e o daemon é o SFK , um servidor FTP básico.

Para o que importa aqui, o script startserv.shpode ser redigido da seguinte maneira:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

Depois de executar o script startserv.sh, ele pára (termina?) Sem mostrar nenhum prompt e, em seguida:

  • CTRL+ Ctermina o script e o processo de trabalho em segundo plano;

  • Ao pressionar Entero script, o processo permanece em segundo plano.

De qualquer forma, só posso vê-lo via pse não jobs, então, quando quero fechar o processo, tenho que enviar um kill -9sinal brutal , algo que gostaria de evitar em favor do CTRL+ C.

Uma alternativa seria executar o script inteiro em segundo plano. 'Seria', mas o readcomando não pode obter a entrada do usuário se o script for executado como startserv.sh &.

Observe que preciso de um servidor efêmero, não um daemon verdadeiro : ou seja, desejo que o processo do servidor seja executado em segundo plano, após o término do script, para executar tarefas simples de shell interativas (com um convidado da máquina virtual), mas não não precisa do processo para sobreviver à concha; portanto, nohupnão parece apropriado.

antonio
fonte
obtenha o ID do processo em execução em segundo plano usando bgproc="$!"e, em seguida, command "$bgproc" execute a ação apropriada. Veja também stackoverflow.com/questions/1908610/…
Valentin Bajrami
Você também pode criar um arquivo PID. Em seguida, leia esse arquivo para ver qual é o número do processo e vá a partir daí.
jgr208

Respostas:

18

Ao pressionar Entero script, o processo permanece em segundo plano.

Quase! Na verdade, o script já saiu quando você pressiona Enter. No entanto, é assim que você pode recuperar seu prompt (porque seu shell imprime $PS1tudo novamente).

A razão pela qual pressionar Ctrl+ Cencerra os dois é porque os dois estão vinculados. Quando você executa seu script, seu shell inicia um subshell no qual executá-lo. Quando você encerra esse subshell, seu processo em segundo plano morre, provavelmente por um SIGHUPsinal.

Separe o script, o processo em segundo plano e o subshell

Usando nohup, você poderá se livrar desse pequeno inconveniente.

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

A disownalternativa

Se você pode alternar de /bin/shpara /bin/bash, também pode tentar disown. Para saber mais, basta digitar help disownuma bashinstância.

disown -h $cmd &

Matando o processo em segundo plano "bem"

Agora, quando se trata de matar o seu processo, você pode perfeitamente fazer um " Ctrl+ C" usando kill. Apenas não envie um brutal SIGKILL. Em vez disso, você pode usar:

$ kill -2 [PID]
$ kill -15 [PID]

O que enviará um bom SIGINT(2) ou SIGTERM(15) para o seu processo. Você também pode imprimir o valor do PID após iniciar o processo:

...
nohup $cmd &
echo $!

... ou melhor ainda, faça com que o script aguarde um SIGINTe envie-o de volta ao processo em segundo plano (isso manterá seu script em primeiro plano) :

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

Se um SIGINTnão for suficiente, basta usar um SIGTERM(15):

trap "kill -15 $bg_pid" 2 15

Desta forma, quando seu script recebe uma SIGINT( Ctrl+ C, kill -2) ou um SIGTERMenquanto waiting para o processo de fundo, ele só vai retransmitir os sinais para ele. Se esses sinais matarem a sfkinstância, a waitchamada retornará, encerrando seu script também :)

John WH Smith
fonte
1
+1 Muito informativo. Como o script é executado em uma subshell, existe alguma possibilidade de acessar do script para a tabela de tarefas do shell pai do script? Ou seja, os trabalhos de lista emitidos jobsno terminal após o término do script (em vez de ps).
antonio
1
Os trabalhos estão associados ao seu shell atual, eles não são transmitidos de um shell para outro. Quando seu subshell morre, seus trabalhos não são recuperados. Ao imprimir o PID do processo em segundo plano, você pode obter informações sobre ele facilmente, mesmo depois que o subshell terminou ( pid -p).
John WH Smith
boa explicação, no entanto, se o seu script contiver mais comandos, eles nunca serão executados (por causa do wait). Se você remover a espera, o processamento do sinal será interrompido: /
chefarov