Esta resposta ao comando da linha de comandos para matar automaticamente um comando após um certo período de tempo
propõe um método de 1 linha para atingir o tempo limite de um comando de longa execução a partir da linha de comando do bash:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Mas é possível que um determinado comando "de longa execução" termine antes do tempo limite. (Vamos chamá-lo de um comando "normalmente de longa execução, mas às vezes rápido", ou tlrbsf por diversão.)
Portanto, essa abordagem bacana de uma linha apresenta alguns problemas. Primeiro, sleep
não é condicional, de modo que define um limite inferior indesejável para o tempo necessário para a sequência terminar. Considere 30s ou 2m ou até 5m para o sono, quando o comando tlrbsf terminar em 2 segundos - altamente indesejável. Segundo, como kill
é incondicional, portanto, essa sequência tentará eliminar um processo que não está em execução e se queixar.
Assim...
Existe uma maneira de atingir o tempo limite de um comando tipicamente de execução longa, mas às vezes rápido ( "tlrbsf" ) que
- possui uma implementação bash (a outra pergunta já possui respostas Perl e C)
- terminará no início dos dois: término do programa tlrbsf ou tempo limite decorrido
- não matará processos inexistentes / não em execução (ou, opcionalmente: não reclamará de uma matança incorreta)
- não precisa ser um liner
- pode ser executado no Cygwin ou Linux
... e, para pontos de bônus, executa o comando tlrbsf em primeiro plano e qualquer processo 'sleep' ou extra em segundo plano, de modo que o stdin / stdout / stderr do comando tlrbsf possa ser redirecionado, mesmo como se tivesse sido correr diretamente?
Nesse caso, compartilhe seu código. Se não, por favor explique o porquê.
Passei um tempo tentando hackear o exemplo mencionado, mas estou atingindo o limite de minhas habilidades no bash.
fonte
timeout
utilitário gnu ?timeout
é ótimo! você pode até usar com vários comandos (script de várias linhas): stackoverflow.com/a/61888916/658497Respostas:
Eu acho que é exatamente isso que você está pedindo:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
fonte
Você provavelmente está procurando o
timeout
comando no coreutils. Como faz parte dos coreutils, é tecnicamente uma solução C, mas ainda é coreutils.info timeout
para mais detalhes. Aqui está um exemplo:fonte
gtimeout
brew install coreutils
e, em seguida, você pode usá-logtimeout
.Esta solução funciona independentemente do modo do monitor do bash. Você pode usar o sinal apropriado para finalizar o seu_command
O observador mata seu_command após um tempo limite determinado; o script aguarda a tarefa lenta e finaliza o observador. Observe que
wait
não funciona com processos que são filhos de um shell diferente.Exemplos:
fonte
wait
retorna o status de saída do processo em que espera. Portanto, se o seu comando sair dentro do tempo alocado, mas com um status de saída diferente de zero, a lógica aqui se comportará conforme expirou, ou seja, imprimayour_command interrupted
. Em vez disso, você pode fazer owait
sem umif
e, em seguida, verificar se o$watcher
pid ainda existe, se existir, você sabe que não expirou.kill
em um caso, maspkill
no outro. Eu precisava usar ospkill
dois para fazer isso funcionar corretamente. Eu esperaria que, se você envolver um comando()
, precisará usápkill
-lo para matá-lo. Mas talvez funcione de maneira diferente se houver apenas um único comando dentro do()
.Ai está:
você pode alterar o
SIGINT
e10
como desejar;)fonte
coreutils
pacote do FreeBSD.Você pode fazer isso inteiramente com
bash 4.3
e acima:_timeout 5 longrunning_command args
{ _timeout 5 producer || echo KABOOM $?; } | consumer
producer | { _timeout 5 consumer1; consumer2; }
Exemplo:
{ while date; do sleep .3; done; } | _timeout 5 cat | less
Precisa do Bash 4.3 para
wait -n
Se você não precisa do código de retorno, isso pode ser ainda mais simples:
Notas:
Estritamente falando, você não precisa o
;
em; )
, no entanto, faz coisa mais consistente ao; }
-Case. E oset +b
provavelmente pode ser deixado de fora também, mas é melhor prevenir do que remediar.Exceto por
--forground
(provavelmente), você pode implementar todos ostimeout
suportes de variantes .--preserve-status
é um pouco difícil, no entanto. Isso é deixado como um exercício para o leitor;)Esta receita pode ser usada "naturalmente" na casca (tão natural quanto para
flock fd
):No entanto, como explicado acima, você não pode reexportar variáveis de ambiente para o shell anexo dessa maneira naturalmente.
Editar:
Exemplo do mundo real: tempo limite
__git_ps1
, caso demore muito (para coisas como links SSHFS lentos):Edit2: Bugfix. Notei que
exit 137
não é necessário e faz_timeout
não confiável ao mesmo tempo.Edit3:
git
é um , por isso precisa de um truque duplo para funcionar satisfatoriamente.Edit4: Esqueceu um
_
no primeiro_timeout
exemplo de GIT do mundo real.fonte
cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status.
De: tiswww.case.edu/php/chet/bash/NEWSEu prefiro "timelimit", que tem um pacote pelo menos no debian.
http://devel.ringlet.net/sysutils/timelimit/
É um pouco melhor do que o "timeout" do coreutils, porque imprime alguma coisa ao interromper o processo e também envia o SIGKILL após algum tempo, por padrão.
fonte
timelimit -t1 ./a_forking_prog
mata apenas um dos dois processos), mas o tempo limite funciona.Para atingir o tempo limite
slowcommand
após 1 segundo:timeout 1 slowcommand || echo "I failed, perhaps due to time out"
Para determinar se o comando expirou ou falhou por seus próprios motivos, verifique se o código de status é 124:
Observe que quando o status de saída é 124, você não sabe se o tempo limite expirou devido ao seu
timeout
comando ou se o comando foi finalizado devido a alguma lógica de tempo limite interno próprio e depois retornou 124. Você pode assumir com segurança em ambos os casos , porém, que um tempo limite de algum tipo aconteceu.fonte
Veja também o script http://www.pixelbeat.org/scripts/timeout, cuja funcionalidade foi integrada em coreutils mais novos
fonte
Meio hacky, mas funciona. Não funciona se você tiver outros processos em primeiro plano (por favor me ajude a corrigir isso!)
Na verdade, acho que você pode revertê-lo, atendendo aos seus critérios de 'bônus':
fonte
o tempo limite é provavelmente a primeira abordagem a tentar. Você pode precisar de notificação ou outro comando para executar se o tempo limite for excedido. Depois de pesquisar e experimentar, criei este script bash :
fonte
Script simples com clareza de código. Salvar em
/usr/local/bin/run
:Tempo limite de um comando que demora muito:
Termina imediatamente para um comando que é concluído:
fonte
Se você já sabe o nome do programa (vamos supor
program
) terminar após o tempo limite (como um exemplo de3
segundos), posso contribuir com uma solução alternativa simples e um tanto suja:Isso funciona perfeitamente se eu chamar processos de benchmark com chamadas do sistema.
fonte
argv[0]
, talvez com outros hacks para criar mais espaço).(sleep 3 && docker stop <container>) &
funcionou bem. Obrigado!{ sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"
Dessa forma, ele matará apenas trabalhos no shell atual.Também há
cratimeout
Martin Cracauer (escrito em C para sistemas Unix e Linux).fonte
O OS X ainda não usa o bash 4, nem possui / usr / bin / timeout, então aqui está uma função que funciona no OS X sem home-brew ou macports semelhante a / usr / bin / timeout (baseado no Tino's responda). A validação de parâmetros, ajuda, uso e suporte para outros sinais são um exercício para o leitor.
fonte
Em 99% dos casos, a resposta NÃO é implementar nenhuma lógica de tempo limite. Timeout lógica é em quase qualquer situação um sinal de aviso vermelho que algo outra coisa está errado e deve ser fixado vez .
Seu processo está travando ou interrompido após n segundos, às vezes? Então descubra o porquê e conserte isso.
Como um aparte, para fazer a solução do strager corretamente, você precisa usar a espera "$ SPID" em vez do fg 1, pois nos scripts você não tem controle de tarefas (e tentar ativá-la é estúpido). Além disso, o fg 1 depende do fato de você não ter iniciado outros trabalhos anteriormente no script, o que é uma suposição ruim a ser feita.
fonte
Foi-me apresentado um problema para preservar o contexto do shell e permitir tempos limite, o único problema é que ele interromperá a execução do script no tempo limite - mas tudo bem com as necessidades que me foram apresentadas:
com as saídas:
é claro que eu assumo que havia um dir chamado
scripts
fonte
fonte
Meu problema foi talvez um pouco diferente: inicio um comando via ssh em uma máquina remota e quero matar o shell e os childs se o comando travar.
Agora uso o seguinte:
Dessa forma, o comando retorna 255 quando houve um tempo limite ou o código de retorno do comando em caso de êxito
Observe que os processos de eliminação de uma sessão ssh são tratados de forma diferente de um shell interativo. Mas você também pode usar a opção -t para ssh para alocar um pseudo terminal, para que ele funcione como um shell interativo
fonte
Aqui está uma versão que não depende de gerar um processo filho - eu precisava de um script independente que incorporasse essa funcionalidade. Ele também faz um intervalo de pesquisa fracionário, para que você possa pesquisar mais rapidamente. o tempo limite teria sido preferido - mas estou preso em um servidor antigo
fonte
Uma maneira muito simplista:
com pkill (opção -f ), você pode matar seu comando específico com argumentos ou especificar -n para evitar o processo antigo.
fonte
Com base na resposta do @ loup ...
Se você deseja exceder o tempo limite de um processo e silenciar a saída kill job / pid, execute:
Isso coloca o processo em segundo plano em um subshell para que você não veja a saída do trabalho.
fonte
Eu tenho um trabalho cron que chama um script php e, algumas vezes, fica preso no script php. Esta solução foi perfeita para mim.
Eu uso:
fonte
scripttimeout
?