Blog Linux Avante

Como repetir um comando a cada X segundos no Linux

10 de dezembro de 2020

Este artigo explica como repetir um comando a cada X segundos no Linux, de duas maneiras: usando watch e usando sleep em um loop de execução while (com uma maneira de evitar flutuação de tempo ao usar comandos em loop longos).

Usando watch para executar um comando a cada X segundos

watch pode executar um comando repetidamente, exibindo sua saída e erros (a primeira tela cheia). Isso permite que você observe a mudança de saída do programa ao longo do tempo.

Usando watch para executar um comando a cada X segundos:

Comandos para usar no terminal

watch -n

Onde:

  • -n especifica o intervalo de tempo
  • X é o intervalo no qual executar o comando, em segundos (com 0,1 segundos sendo o menor valor possível)
  • comando é o comando que você deseja executar

Se o comando contiver barras verticais, aspas ou outros caracteres especiais, use aspas simples, por exemplo: 'comando'.

Exemplo. O seguinte comando executa ps aux | grep firefox a cada 5 segundos:

Comandos para usar no terminal

watch -n 5 'ps aux | grep firefox'

O comando watch tem algumas opções, como destacar as diferenças entre atualizações sucessivas (--differences/-d), beep se um comando tem uma saída diferente de zero (--beep/-b), e muito mais. Verifique sua página man para obter mais informações.

Usando sleep em um loop while para repetir um comando a cada X segundos

Outra maneira de repetir um comando a cada X segundos no Linux é usar um loop while com o comando sleep:

Comandos para usar no terminal

while true; do ; sleep ; done

Aqui, você precisa substituir comando com o comando a ser executado e X com o intervalo de tempo em segundos (o número não precisa ser um inteiro, mas não pode ser negativo; você também pode especificar minutos - 1m por exemplo, horas - 1h por exemplo, etc. .).

Exemplo. O seguinte one-liner executa o comando echo $(date) a cada 5 segundos:

Comandos para usar no terminal

while true; do echo $(date); sleep 5; done

Se você estiver fazendo algo mais complicado, certifique-se de que o intervalo seja menor do que o tempo necessário para o comando terminar, ou então isso pode interferir em algo em seu script.

Também é importante notar que usando isso, o tempo irá variar, dependendo de quanto tempo o comando que você está executando leva para ser concluído. Por exemplo, se você deseja executar um comando a cada 5 segundos, mas esse comando leva 3 segundos para ser concluído, isso fará com que o comando seja executado a cada 8 segundos, em vez de a cada 5 segundos.

Uma solução para evitar essa flutuação de tempo e executar o comando a cada X segundos, independentemente de quanto tempo leva para ser concluído (desde que o comando não leve mais para ser concluído do que o tempo de suspensão), é usar o seguinte:

Comandos para usar no terminal

while true; do ; sleep $(( - $(date +%s) % )); done

Aqui, substitua comando pelo comando que deseja executar e ambas as instâncias de X com o número de segundos após o qual o comando deve ser repetido.

Atenção: Esta solução não é perfeita. Leia a explicação e a alternativa para isso nas edições marcadas mais adiante neste artigo.

Exemplo. O seguinte one-liner repete o comando sleep 3 (não poderia pensar em um exemplo melhor agora de um comando que leva alguns segundos para ser concluído e não é destrutivo de forma alguma caso o usuário não o interrompa - Estou digitando às 5h) a cada 5 segundos:

Comandos para usar no terminal

while true; do sleep 3; sleep $((5 - $(date +%s) % 5)); done

Usando isso, embora o comando (sleep 3 neste caso, pode ser qualquer comando que você deseja) leve 3 segundos para ser concluído, o intervalo entre as execuções é de 5 segundos.

Para testar isso, você pode adicionar um echo $(date) no início, como este:

Comandos para usar no terminal

while true; do echo $(date); sleep 3; sleep $((5 - $(date +%s) % 5)); done

Você perceberá que a data impressa no terminal está em incrementos de 5 segundos, como este:

Thu 10 Dec 05:48:00 2020

Thu 10 Dec 05:48:05 2020

Thu 10 Dec 05:48:10 2020

Thu 10 Dec 05:48:15 2020

Atenção: Esta solução não é perfeita. Entre a primeira e a segunda execução, o intervalo de tempo pode ser menor do que o especificado. No entanto, as execuções subsequentes usam o intervalo de tempo correto. Se você conhece a melhor maneira de fazer isso, deixe um comentário abaixo.

Dica: Uma solução (via stackexchange) que evita flutuação no tempo e não tem o problema que mencionei acima (portanto, nenhum intervalo de tempo diferente entre a primeira e a segunda execução), mas que não faz uso do comando sleep, é o seguinte comando de uma linha:**

Comandos para usar no terminal

while true; do currentTime=$(date +%s); elapsedTime=$((currentTime - lastTime)); if [ $elapsedTime -ge ]; then ; lastTime=$currentTime; i=0; fi; done

Substitua X com o intervalo de tempo entre as execuções (em segundos) e comando com o comando que deseja repetir a cada X segundos.

Uma pequena explicação é necessária aqui. Este loop while armazena o tempo Unix atual como currentTime e, em seguida, subtrai o último tempo (lastTime) do tempo atual, armazenando como elapsedTime. Em seguida, ele verifica se o tempo decorrido é maior ou igual a X e se for, ele executa command (então o comando é repetido a cada X segundos). E, finalmente, ele define o último tempo para ser igual ao tempo atual, portanto, da próxima vez que for executado, ele pode subtrair lastTime do currentTime, o que dá o valor elapsedTime. Espero que isso faça sentido para você como faz na minha cabeça 😁️.

Exemplo. A seguinte linha repete os comandos echo $(date) e sleep 2 (usei sleep 2, portanto, o comando leva alguns segundos para ser verificado, se não for concluído).

Comandos para usar no terminal

while true; do currentTime=$(date +%s); elapsedTime=$((currentTime - lastTime)); if [ $elapsedTime -ge 5 ]; then echo $(date); sleep 2; lastTime=$currentTime; i=0; fi; done

Você também pode gostar de: Como excluir arquivos mais antigos ou mais recentes do que N dias usando find (com exemplos extras)

Confira a versão original desse post em inglês
Propaganda
Blog Comments powered by Disqus.
Propaganda