Como matar um programa se ele não produzir nenhuma saída em um determinado tempo limite?

2

Eu quero detectar quando algum processo está parado, mas isso não me dá nenhuma pista sobre o assunto. Tudo o que sei é que, se não produzir nenhuma saída em um determinado tempo limite (digamos 30 segundos), isso significa que ela provavelmente está bloqueada.

Eu conheço o programa timeout do coreutils, mas é baseado no tempo de saída do programa completo, não na última linha do tempo de saída. Eu adoraria se algo assim funcionasse:

timeout --stdout --stderr 30s my-program

Então, há alguma maneira de fazer isso? Como posso fazer isso?

    
por Yajo 21.03.2018 / 13:09

3 respostas

1

O código

Salve isso como tkill (torne-o executável e ajuste seu PATH se necessário):

#!/bin/bash

_terminate_children() {
        trap "exit 143" SIGTERM && kill -- -$$
}

trap _terminate_children SIGINT SIGTERM

tout="$1"
shift
eval $@ | tee >(while :; do
   read -t "$tout"
   case $? in
      0) : ;;
      1) break ;;
      *) _terminate_children ;;
   esac
done)
exit ${PIPESTATUS[0]}

Uso básico

tkill 30 some_command

O primeiro argumento ( 30 aqui) é o tempo limite em segundos.

Notas

  • tkill espera que some_command gere saída de texto (não binário).
  • tkill probes stdout do comando fornecido. Para incluir stderr , redirecione-o como no último exemplo avançado abaixo.

Uso avançado

Estes são exemplos válidos:

tkill 9 foo -option value
tkill 9 "foo -option value"  # equivalent to the above
tkill 5 "foo | bar"
tkill 5 'foo | bar'
tkill 5 'foo | bar | baz'    # tkill monitors baz
tkill 5 'foo | bar' | baz    # baz reads from tkill
tkill 3 "foo; bar"
tkill 6 "foo && bar || baz"
tkill 7 "some_command 2>&1"

Use a sintaxe Bash nessas citações.

Sair do status

  • Se some_command sair sozinho, seu status de saída será reutilizado como o status de saída de tkill ; tkill 5 true retorna 0 ; tkill 5 false retorna 1 ; tkill 5 "true; false" retorna 1 .
  • Se o tempo limite determinado expirar ou tkill for interrompido por SIGINT ou SIGTERM , o status de saída será 143 .

Fragmentos de código explicados

  • eval torna os exemplos avançados possíveis.
  • tee nos permite analisar stdin enquanto ainda passamos uma cópia para stdout .
  • read -t é responsável por aplicar o tempo limite, seu status de saída é usado para determinar o que fazer a seguir.
  • Comandos monitorados são eliminados quando necessário com esta solução .
  • O status de saída dos comandos monitorados é recuperado com esta solução .
por 26.03.2018 / 10:59
0

Então, basicamente algo assim:

#!/bin/bash
tmp1=/tmp/tmp-$$-1
tmp2=/tmp/tmp-$$-2
touch $tmp1
touch $tmp2

time_out=30

typeset -i i

i=0
my-program > $tmp1 &
pgmpid=$!

while ps $pgmpid > /dev/null ; do
    sleep 1
    if diff $tmp1 $tmp2 > /dev/null ; then
        i=i+1
        if [ $i -gt $time_out ] ; then
            kill $pgmpid
        fi
    else
        i=0
        cp $tmp1 $tmp2 
    fi
done

rm -f $tmp1 $tmp2
    
por 22.03.2018 / 19:23
0

Execute o programa em segundo plano enquanto copia a saída para um arquivo. Após 30 segundos, se o arquivo estiver vazio, termine o programa, ou traga-o de volta em primeiro plano.

my-program | tee temp-file & 
sleep 30
[ -s temp-file ] && kill $! || fg $!
    
por 23.03.2018 / 13:13

Tags