Mate o programa depois que ele gerar uma determinada linha, a partir de um shell script

9

Histórico:

Estou escrevendo um script de teste para um software de biologia computacional. O software que estou testando pode demorar dias ou até semanas para ser executado, então ele tem uma funcionalidade de recuperação incorporada, no caso de travamentos do sistema ou falhas de energia.

Estou tentando descobrir como testar o sistema de recuperação. Especificamente, não consigo descobrir uma maneira de "travar" o programa de maneira controlada. Eu estava pensando em alguma forma de sincronizar uma instrução SIGKILL para correr depois de algum tempo. Isso provavelmente não é o ideal, já que o caso de teste não tem a garantia de executar a mesma velocidade todas as vezes (ele é executado em um ambiente compartilhado), portanto, comparar os logs com a saída desejada seria difícil.

Este software imprime uma linha para cada seção de análise que é concluída.

Pergunta:

Eu queria saber se havia uma maneira boa / elegante (em um script de shell) para capturar a saída de um programa e depois matar o programa quando uma determinada linha / nº de linhas é gerada pelo programa?

    
por Paul 20.03.2012 / 20:39

5 respostas

3

Um script de wrapper como este é uma abordagem padrão. O script executa o programa em segundo plano e, em seguida, faz um loop, verificando o arquivo de log a cada minuto para alguma string. Se a string for encontrada, o programa em segundo plano será eliminado e o script será encerrado.

command="prog -foo -whatever"
log="prog.log"
match="this is the what i want to match"

$command > "$log" 2>&1 &
pid=$!

while sleep 60
do
    if fgrep --quiet "$match" "$log"
    then
        kill $pid
        exit 0
    fi
done
    
por 20.03.2012 / 21:27
11

Se o seu programa terminar no SIGPIPE (que é a ação padrão), deve ser o suficiente para enviar a saída para um leitor que sairá ao ler a linha.

Então, pode ser tão simples quanto

$ program | sed -e '/Suitable text from the line/q'

Se você quiser suprimir o uso de saída padrão

$ program | sed -n -e '/Suitable text from the line/q'

Da mesma forma, se alguém quiser parar após um certo número de linhas, pode-se usar a cabeça no lugar de sed, por exemplo,

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

A hora exata em que ocorre o kill depende do comportamento de buffer do terminal, como o stardt sugere nos comentários.

    
por 20.03.2012 / 22:41
6

Como alternativa à resposta do dmckee, o comando grep com a opção -m (veja, por exemplo, Este comando man page também pode ser usado:

compbio | grep -m 1 "Text to match"

para quando 1 linha correspondente ao texto for encontrada ou

compbio | grep -v -m 10 "Text to match"

para aguardar 10 linhas que não correspondem ao texto especificado.

    
por 21.03.2012 / 00:22
2

Você pode usar expect(1) para assistir a stdout de um programa e executar uma ação predefinida em alguns padrões.

#!/usr/bin/env expect

spawn your-program -foo -bar 
expect "I want this text" { close }

Ou um one-liner para incorporar em outro script:

expect -c "spawn your-program -foo -bar; expect \"I want this text\" { close }"

Observe que o comando expect não vem com todos os sistemas operacionais por padrão. Você pode precisar instalá-lo.

    
por 07.07.2016 / 02:33
1

Você pode usar uma instrução "while":

Você precisa canalizar a saída do seu software (ou de seus logs) e, em seguida, para cada nova linha, fazer um teste de condição e executar kill -KILL. Por exemplo (eu testei com / var / log / messages como logfile):

tail -f /var/log/messages | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Ou com o software diretamente:

./biosoftware | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

Você precisa substituir o caminho do log / nome do aplicativo, a linha a ser correspondida e o PID para matar (você também pode usar o killall).

Boa sorte com o seu software,

Hugo,

    
por 20.03.2012 / 21:22

Tags