Existem (pelo menos) dois programas que fornecem essa funcionalidade:
NOME
timelimit
- limitar efetivamente o tempo absoluto de execução de um processo
SINOPSE
timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]
e
NOME
timeout
- execute um comando com um limite de tempo
SINOPSE
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
Eles são empacotados da seguinte maneira:
$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout
Comparação:
/-----------------------------+------------+----------------\
| Feature | timelimit | timeout |
+=============================+============+================+
| time to run | -t time | first argument |
+-----------------------------+------------+----------------+
| terminate signal | -s signal | -s signal |
+-----------------------------+------------+----------------+
| grace period | -T time | -k time |
+-----------------------------+------------+----------------+
| kill signal | -S signal | (note 1) |
+-----------------------------+------------+----------------+
| propagate signals | -p | (note 2) |
\-----------------------------+------------+----------------/
Notas:
timeout
sempre usa SIGKILL
como sinal de último recurso.
timeout
não possui nenhuma funcionalidade para sair com um sinal quando o programa filho o faz.
O status de saída dos dois programas é diferente, mas é difícil resumir bem, por isso sugiro que você consulte as páginas de manual.
Como timeout
é instalado em mais sistemas por padrão ( coreutils
é um pacote padrão em muitas distribuições), sugiro que você use isso, a menos que precise da funcionalidade extra fornecida por timelimit
.
timelimit
. Veja Como posso matar um processo e verifique se o PID não foi reutilizado para obter mais informações sobre eles e sobre o tempo limite do GNU.timeout
está incluída no GNU coreutils ,timelimit
não é. Você pode ter instalado nenhum, um ou ambos. No segundo, é relatado que o limite de tempo executa um comando e finaliza o processo gerado após um determinado tempo com um determinado sinal. Um sinal de “aviso” é enviado primeiro e, depois de um tempo limite, um sinal de “morte”, semelhante à maneira como init (8) opera no desligamento. Portanto, mesmo um comportamento diferente no meio .timeout
é o caminho a percorrer.Na verdade,
timeout
é para isso:fonte
Pure
bash
construído em, sem coreutilsDescobri que esta solução funciona em
bash
depender de um built-in comando sem chamar um executável externo. Funciona em sistemas onde, eventualmente, nem sequer são instalados os coreutils [ 1 ]Explicações : como de costume quando você enviar um comando no fundo com
&
, seu PID é armazenado na variável interna$!
(presente na versão modernadash
,csh
,bash
,tcsh
,zsh
...).O que realmente faz a diferença entre as conchas é a presença do built-in comando
read
[ 2 ] e da opção-t
. Na 1ª versão, se o usuário não concluir uma linha de entrada antes da quantidade especificada de segundos, a instrução será encerrada e um código de retorno de erro será gerado.A segunda versão funciona como a 1ª, mas você pode abortar o tempo limite final pressionando enter.
De fato, o operador ou
||
executa akill
instrução somente se oread
comando sair com um código de retorno diferente de zero, como quando o tempo limite expirar. Se você pressionar enterantes desse momento, ele retornará 0 e não matará seu comando anterior.Soluções Coreutils [ 1 ]
Quando coreutils estão presentes em seu sistema e você não tem nenhuma necessidade de economizar o tempo e os recursos para chamar um programa externo,
timeout
esleep
e são ambos excelentes maneiras para alcançar seu objetivo.timeout
O uso detimeout
é direto.Eventualmente, você pode considerar usar também a
-k
opção de enviar um sinal de interrupção adicional se o primeiro falhar.sleep
Comsleep
você, você pode usar sua fantasia ou inspirar-se [ 3 ] . Observe que você pode deixar seu comando em segundo plano ou em primeiro plano (por exemplo,top
geralmente precisa estar em primeiro plano).Explicações
YourCommand
e, em seguida, seu shellsleep
fica por 5 minuites. Quando terminar, o último processo em segundo plano ($!
) será eliminado. Você para sua concha.YourCommand
e armazena imediatamente esse PID na variável$pid
. Em seguida, você executa em segundo plano uma soneca de 5 minutos e seu consequente comando que mata o PID armazenado. Como você enviou esse grupo de comandos em segundo plano, não interrompe seu shell. Você precisa armazenar o PID em uma variável porque o valor de$!
pode ser atualizado por uma eventual execução de outro programa em segundo plano. Em palavras simples, você evita o risco de matar o processo errado ou nenhum processo.$$
, e então é executado seu comando que permanece em primeiro plano.()
que armazena seu PID em uma variável (cmdpid
) e se mata com outro subshell enviado na execução em segundo plano, depois executa YourCommand em primeiro plano.É claro que em cada versão você pode enviar o sinal de interrupção necessário, do padrão ao extremo
kill -9
, para ser usado apenas quando realmente necessário.Referências
fonte
Para o seu caso particular, a maioria das implementações de
ping
suporte-c
ou--count
para finalizar após um número específico de pings:Para uma solução mais geral, consulte as outras respostas.
fonte
ping
um exemplo concreto. Ele não quer uma solução caso a caso para cada programa diferente.Você pode fazer isso com um script simples como este:
(sinal SIGINT = 2 usado conforme sugestão de Matija Nalis no comentário abaixo).
Uma explicação da expressão bash (incomum?)
$@:...
: Os parâmetros posicionais, ($*, $@, "$*", "$@"
) admitem a seguinte especificação extra, por exemplo:o que significa: de todos os parâmetros, pegue COUNT deles, sendo o primeiro deles o da posição STARTth; se COUNT for omitido, leve todos eles até o final, começando com a posição STARTth. Lembre-se de que
$0
é o nome do programa. Se START for negativo, comece a contar a partir do final e lembre-se de que COUNT não pode ser negativo; portanto, o último argumento é"${@:-1}"
. Além disso, sempre inclua os parâmetros posicionais entre aspas duplas.fonte
$1
é bastante nojento. Além disso, você poderia apenassleep "$1"
ou algo assimcountdown
.time=$1; shift
e, em seguida, você não precisa da sintaxe de divisão da matriz para os parâmetros posicionais. Mas sim, isso é muito mais simples.ctrl-c
, provavelmente é melhor tentar emkill -INT
vez dekill -9
(ou pelo menos tentar-9
apenas depois de alguns segundos se o primeiro não foi bem-sucedido - isso dá ao programa a chance de sair de forma limpa e não deixar arquivos temporários etc)Desde que você mencionou
ping
no seu exemplo; este comando tem algumas opções para parar após um período específico de tempo:fonte