Estou procurando uma maneira de limpar a bagunça quando meu script de nível superior terminar.
Especialmente se eu quiser usar set -e
, gostaria que o processo em segundo plano morresse quando o script sair.
Para limpar alguma bagunça, trap
pode ser usado. Pode fornecer uma lista de coisas executadas quando um sinal específico chega:
trap "echo hello" SIGINT
mas também pode ser usado para executar algo se o shell sair:
trap "killall background" EXIT
É um builtin, portanto help trap
, você fornecerá informações (funciona com o bash). Se você quiser apenas matar trabalhos em segundo plano, poderá fazer
trap 'kill $(jobs -p)' EXIT
Cuidado para usar o single '
, para impedir que o shell substitua o $()
imediatamente.
kill $(jobs -p)
não funciona no traço, porque ele executa a substituição de comando em um subshell (ver Command Substituição no homem traço)killall background
suposto ser um espaço reservado?background
não está na página de manual ...Isso funciona para mim (aprimorado graças aos comentaristas):
kill -- -$$
envia um SIGTERM para todo o grupo de processos, matando também descendentes.A especificação do sinal
EXIT
é útil ao usarset -e
(mais detalhes aqui ).fonte
4.3.30(1)-release
OSX e também está confirmado no Ubuntu . Há uma wokaround obvoius , embora :)-$$
. Ele avalia como '- <PID> `por exemplo-1234
. Na página de manual kill // página de manual interna, um traço inicial especifica o sinal a ser enviado. No entanto - provavelmente bloqueia isso, mas o traço principal não está documentado de outra forma. Qualquer ajuda?man 2 kill
, que explica que quando um PID é negativo, o sinal é enviado para todos os processos no grupo de processos com o ID fornecido ( en.wikipedia.org/wiki/Process_group ). É confuso que isso não seja mencionado emman 1 kill
ouman bash
e possa ser considerado um bug na documentação.Atualização: https://stackoverflow.com/a/53714583/302079 aprimora isso adicionando o status de saída e uma função de limpeza.
Por que converter
INT
eTERM
sair? Porque ambos devem acionar okill 0
sem inserir um loop infinito.Por gatilho
kill 0
onEXIT
? Como saídas de script normais devem acionarkill 0
.Por que
kill 0
? Porque subcascas aninhadas precisam ser mortas também. Isso derrubará toda a árvore do processo .fonte
kill 0
significa / faz?Eu faria apenas pequenas alterações na resposta de Johannes e usaria jobs -pr para limitar a interrupção dos processos em execução e adicionar mais alguns sinais à lista:
fonte
A
trap 'kill 0' SIGINT SIGTERM EXIT
solução descrita na resposta do @ tokland é muito boa, mas o Bash mais recente falha com uma falha de segmantação ao usá-lo. Isso porque o Bash, a partir da versão 4.3, permite a recursão de interceptação, que se torna infinita neste caso:SIGINT
ouSIGTERM
ouEXIT
;kill 0
, que enviaSIGTERM
para todos os processos do grupo, incluindo o próprio shell;Para solucionar isso, cancele o registro manual da armadilha:
A maneira mais elegante, que permite imprimir o sinal recebido e evita mensagens "Terminated:":
UPD : exemplo mínimo adicionado;
stop
Função aprimorada para evitar a captura de sinais desnecessários e ocultar as mensagens "Terminadas:" da saída. obrigado Trevor Boyd Smith pelas sugestões!fonte
stop()
que você fornecer o primeiro argumento como o número de sinal, mas depois você codificar o que sinais estão sendo registro cancelado. em vez de codificar os sinais que estão sendo cancelados o registro, você pode usar o primeiro argumento para cancelar o registro nastop()
função (isso poderia interromper outros sinais recursivos (exceto os 3 codificados permanentemente)).SIGINT
, maskill 0
enviaSIGTERM
, que ficará preso novamente. Isso não produzirá recursão infinita, porém, porqueSIGTERM
será retido durante a segundastop
chamada.trap - $1 && kill -s $1 0
deve funcionar melhor. Vou testar e atualizar esta resposta. Obrigado pela boa ideia! :)trap - $1 && kill -s $1 0
não funcionaria também, pois não podemos matarEXIT
. Mas é realmente suficiente capturarTERM
, porquekill
envia esse sinal por padrão.EXIT
, otrap
manipulador de sinal sempre é executado apenas uma vez.Por segurança, acho melhor definir uma função de limpeza e chamá-la de trap:
ou evitando a função completamente:
Por quê? Porque simplesmente usando
trap 'kill $(jobs -pr)' [...]
uma parte do princípio de que não vai ser trabalhos de fundo em execução quando a condição armadilha é sinalizado. Quando não há trabalhos, será exibida a seguinte mensagem (ou similar):porque
jobs -pr
está vazio - terminei nessa 'armadilha' (trocadilhos).fonte
[ -n "$(jobs -pr)" ]
não funciona no meu bash. Eu uso o GNU bash, versão 4.2.46 (2) -release (x86_64-redhat-linux-gnu). A mensagem "kill: use" continua aparecendo.jobs -pr
não retornar os PIDs dos filhos dos processos em segundo plano. Não destrói toda a árvore do processo, apenas apara as raízes.Uma boa versão que funciona com Linux, BSD e MacOS X. Primeiro, tente enviar o SIGTERM e, se não tiver êxito, interrompe o processo após 10 segundos.
Observe que os trabalhos não incluem processos de netos.
fonte
Como https://stackoverflow.com/a/22644006/10082476 , mas com código de saída adicionado
fonte
Outra opção é ter o script definido como o líder do grupo de processos e prender um killpg no seu grupo de processos na saída.
fonte
Então escreva o carregamento do script. Execute um
killall
comando (ou o que estiver disponível no seu sistema operacional) que é executado assim que o script é concluído.fonte
jobs -p não funciona em todos os shells se chamado em um sub-shell, possivelmente a menos que sua saída seja redirecionada para um arquivo, mas não para um canal. (Presumo que ele foi originalmente destinado apenas para uso interativo.)
E o que se segue:
A chamada para "jobs" é necessária com o shell do Debian, que falha ao atualizar o job atual ("%%") se ele estiver ausente.
fonte
Fiz uma adaptação da resposta do @ tokland combinada com o conhecimento de http://veithen.github.io/2014/11/16/sigterm-propagation.html quando percebi que
trap
isso não é acionado se eu estiver executando um processo em primeiro plano (sem fundo&
):Exemplo disso funcionando:
fonte
Apenas pela diversidade, publicarei variações de https://stackoverflow.com/a/2173421/102484 , porque essa solução leva à mensagem "Terminado" no meu ambiente:
fonte