Killing um script de shell em execução em segundo plano

8

Eu escrevi um script de shell para monitorar um diretório usando o utilitário inotifywait de inotifyt-tools. Eu quero que esse script seja executado continuamente em segundo plano, mas também quero ser capaz de pará-lo quando desejar.

Para fazê-lo funcionar continuamente, usei while true ; assim:

while true;
do #a set of commands that use the inotifywait utility
end

Eu salvei-o em um arquivo em /bin e o tornei executável. Para executá-lo em segundo plano, usei nohup <script-name> & e fechei o terminal.

Eu não sei como faço para parar este script. Eu olhei para as respostas aqui e uma questão muito relacionada < href="https://unix.stackexchange.com/questions/79441/terminating-a-bash-shell-script-running-in-the-background"> aqui . Mas eu não consigo resolver o problema.

P.S: Me desculpe se isso soa trivial, eu sou um iniciante em scripts de shell.

UPDATE 1: Com base na resposta de @InfectedRoot abaixo, consegui resolver meu problema usando a seguinte estratégia. Primeiro uso

ps -aux | grep script_name

e use sudo kill -9 <pid> para eliminar os processos. Eu tive que pgrep inotifywait e use sudo kill -9 <pid> novamente para o id retornado.

Isso funciona, mas acho que essa é uma abordagem confusa, estou procurando uma resposta melhor.

UPDATE 2: A resposta consiste em matar 2 processos . Isso é importante porque executar o script na linha de comando inicia 2 processos, 1 o próprio script e 2, o processo inotify . Por favor, sugira se o meu entendimento está correto. Obrigado !!

    
por light94 13.12.2014 / 07:15

4 respostas

5

Para melhorar, use killall e combine os comandos:

ps -aux | grep script_name
killall script_name inotifywait

Ou faça tudo em uma linha:

killall 'ps -aux | grep script_name | grep -v grep | awk '{ print $1 }'' && killall inotifywait
    
por 13.12.2014 / 08:12
3

Relacione os trabalhos em segundo plano usando

# jobs

Em seguida, escolha o número anterior de trabalho e execute

exemplo

# fg 1 

traráparaoprimeiroplano.

Emseguida,mate-ousandoCTRL+CouumamaneiramaisfácildeencontraroPIDdoscriptusando

ps-aux|grepscript_name

Em seguida, mate usando pid

sudo kill -9 pid_number_here
    
por 13.12.2014 / 07:27
2

Você pode usar ps + grep ou pgrep para obter o processo nome / pid ; depois use killall / pkill para matar o nome do processo ou use kill para matar o pid. Todos os seguidores devem funcionar.

killall $(ps aux | grep script_name | grep -v grep | awk '{ print $1 }') && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $1 }' | xargs killall) && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $2 }' | xargs kill) && killall inotifywait
(pgrep -x script_name | xargs kill) && pkill -x inotifywait
pkill -x script_name && pkill -x inotifywait

O mais importante é que você tenha certeza de matar apenas o (s) processo (s) exato (s) que você espera matar.

pkill / pgrep corresponde a um padrão em vez do nome exato , por isso é mais perigoso; aqui -x é adicionado para corresponder ao nome exato.

Além disso, ao usar pgrep / pkill , você pode precisar

  • -f para corresponder à linha de comando completa (como ps aux )
  • -a para também imprimir o nome do processo.
por 13.12.2014 / 10:33
1

Como você provavelmente sabe, há muitas maneiras de fazer isso.

Em relação ao seu "UPDATE # 2" - em geral, encerrar qualquer processo em uma hierarquia pai-filho geralmente terminará todos os processos associados. Mas há muitas exceções para isso. O ideal é que você termine o 'filho' final em uma árvore de processos, então o (s) pai (s) desta criança deve sair se não tiver outras tarefas para executar. Mas se você mata um dos pais, o sinal deve ser transmitido para as crianças quando o pai morre e os filhos devem sair também - mas há casos em que os processos filhos podem ignorar o sinal (via armadilhas ou mecanismos similares) e continuar para executar um será herdado pelo processo 'init' (ou similar). Mas esse assunto de comportamento de processo pode se tornar complexo e eu vou deixar isso lá ...

Um método que eu gosto, se eu não quiser usar um script de controle (descrito a seguir) é usar o utilitário 'screen' para iniciar e gerenciar o processo. O comando 'screen' está cheio de recursos e pode levar algum tempo para dominar. Eu o encorajaria a ler a página de manual 'screen' para uma explicação completa. Um exemplo rápido para iniciar um processo em segundo plano seria o comando:

tela -d -m / caminho / para / programa

Isto irá iniciar "/ path / to / program" dentro de uma sessão de 'screen'.

Você pode ver sua sessão em execução com o comando:

tela -ls

E a qualquer momento você pode se reconectar ao seu programa em execução com o comando:

tela -r

E depois terminá-lo com um ^ C ou o que for.

Além da beleza de ser capaz de se reconectar e desconectar do seu processo à vontade, o 'screen' irá capturar qualquer stdout () que o seu programa possa produzir.

Mas minha preferência pessoal nessas questões é ter um programa de controle que administre o início e a interrupção de um processo. Isso pode ficar um pouco complicado e requer alguns scripts complicados. E como qualquer script, existem dezenas de boas maneiras de fazer isso. Eu incluí um exemplo básico de um método que uso rotineiramente para iniciar e parar aplicativos. Se sua tarefa é simples, você pode inseri-la diretamente no script de controle - ou você pode fazer com que este script de controle chame outro programa externo. Observe que este exemplo não é abrangente em termos de gerenciamento do processo. Deixei de fora a possibilidade de cenários como: Certificar-se de que o script ainda não esteja em execução quando você usa a opção "start", validando que o PID em execução é realmente o processo iniciado (por exemplo, seu script não morreu e outro processo foi iniciado usando o mesmo PID) e validando que o script realmente respondeu (saiu) na primeira solicitação de "kill". Fazer todas essas verificações pode ficar complicado e eu não queria tornar o exemplo muito longo e complexo. Você pode querer modificar o exemplo para praticar seu script de shell.

Salve o seguinte código em um arquivo chamado "programctl", torne-o executável com o comando:

chmod 755 programctl

Em seguida, edite o arquivo e adicione seu código / script na seção de casos que começa com "myscript".

Quando tudo estiver pronto, supondo que o "programctl" esteja no diretório atual, você pode iniciar seu programa com:

./ programctl start

E pare com:

./ programctl stop

Felicidades.

#!/bin/bash
# Description:  A wrapper script used to stop/start another script.

#--------------------------------------
# Define Global Environment Settings:
#--------------------------------------

# Name and location of a persistent PID file

PIDFILE="/tmp/tmpfile-$LOGNAME.txt"

#--------------------------------------
# Check command line option and run...
# Note that "myscript" should not
# provided by the user.
#--------------------------------------

case $1
in
    myscript)
        # This is where your script would go.
        # If this is a routine 'bash' shell script, you can enter
        # the script below as illustrated in the example.  
        # Or you could simply provide the path and parameters
        # to another script such as /dir/name/command -options

        # Example of an embedded script:

        while true
        do
            # do something over and over...
            sleep 1
        done

        # Example of an external script:

        /usr/local/bin/longrun -x
    ;;

    start)
        # Start your script in the background.
        # (Note that this is a recursive call to the wrapper
        #  itself that effectively runs your script located above.)
        $0 myscript &

        # Save the backgound job process number into a file.
        jobs -p > $PIDFILE

        # Disconnect the job from this shell.
        # (Note that 'disown' command is only in the 'bash' shell.)
        disown %1

        # Print a message indicating the script has been started
        echo "Script has been started..."
    ;;

    stop)
        # Read the process number into the variable called PID
        read PID < $PIDFILE

        # Remove the PIDFILE
        rm -f $PIDFILE

        # Send a 'terminate' signal to process
        kill $PID

        # Print a message indicating the script has been stopped
        echo "Script has been stopped..."
    ;;

    *)
        # Print a "usage" message in case no arguments are supplied
        echo "Usage: $0 start | stop"
    ;;
esac
    
por 17.12.2014 / 06:39