Personalizado “coletor de lixo” para fechar manualmente um programa

0

Estou executando o Ubuntu 16.04

Eu tenho esse processo X sendo executado de vários tty. Eu corro de outros pseudo terminais usando o comando screen e também é executado a partir do crontab.

Este programa é iniciado a partir de um script python que é iniciado a partir de um script bash.

Às vezes, o script python recebe uma exceção que não consigo capturar e deixa esse processo X em execução.

Eu gostaria de matar este processo X no final do script, mas para evitar matar outros processos X que estão sendo executados de outros terminais.

Eu pensei em fazer o pgrep para processar o X que não está associado a outros terminais usando o argumento -t, mas não consegui entender a sintaxe da documentação.

    
por A.S.F Studio 11.12.2016 / 08:43

1 resposta

1

Inicie um novo grupo de processos para o código Python (usando o setsid utilitário) e quaisquer outros processos (incluindo o próprio aplicativo), assim você pode matar todo o grupo de processos, se necessário.

Você pode usar a seguinte construção para fazer isso:

exec 3>&1
pgid=$(exec setsid bash -c 'echo $$; exec >&3-; exec COMMAND...')

onde COMMAND... é o comando e seus parâmetros que você normalmente iniciaria. Observe que ele está entre aspas simples e que o comando a ser executado deve ser avaliavel como uma string (em oposição a uma expressão de shell normal).

O primeiro redirecionamento, 3>&1 , copia o descritor de saída padrão para o descritor 3. O redirecionamento >&3- move o descritor 3 para a saída padrão.

O $(...) executa o ... e avalia os dados que ele gravou na saída padrão. Acima, lemos a saída padrão na variável do shell pgid .

O subshell ( ... ) é substituído pelo utilitário setsid , que executa seu argumento em uma nova sessão (grupo de processos). Aqui, ele executa bash , que imprime o processo atual PID ( $$ ), move a saída padrão original do descritor 3 para trás e se substitui / executa o COMMAND... desejado.

O shell executará essa linha enquanto o COMMAND... for executado e só avançará para a próxima linha após a saída de COMMAND... .

Se o COMMAND... deixar processos espúrios em execução e você quiser eliminá-los, tudo que você precisa fazer é executar

kill -SIGNAL -$pgid

A questão é qual sinal enviar. KILL eliminará imediatamente os processos restantes no grupo de processos, por isso é a opção mais simples. No entanto, se os processos se comportarem bem, você poderá pedir que eles saiam enviando-lhes um sinal TERM . É claro que, às vezes, os processos podem ficar em estado instável, de modo que não reajam a TERM e precisem ser KILL ed. Para resolver isso, você pode usar um pequeno loop e ps para ver se ainda há algum processo:

retries=50
while ((1)); do

    # Processes left?
    left=$(ps -o pid= -s $pgrp)
    [ -n "$left" ] || break

    # Ask them to terminate.
    kill -TERM $left

    # Wait 0.1 seconds.
    sleep .1

    # Decrement the retry counter.
    ((--retries > 0)) || break
done

# If there are any processes left in the group,
# send them a KILL signal.
left=$(ps -o pid= -s $pgrp)
[ -n "$left" ] && kill -KILL $left

Observe que as 50 tentativas (0,1 segundo cada) significam que isso espera apenas até 5 segundos antes de enviar um sinal de eliminação. Isso pode não ser um valor adequado, dependendo do aplicativo e do tipo de hardware em execução. Por exemplo, se a máquina for um laptop, e o aplicativo salvar algum histórico ou registros em vários arquivos, e a unidade estiver dormindo no ponto de saída, aumentarei o atraso para talvez 15 a 30 segundos. / p>     

por 11.12.2016 / 11:56