Executar comando após um certo período de tempo?

23

Se estou executando um processo longo, há alguma maneira de executar alguns comandos baseados em tempo?

Por exemplo, estou executando um processo muito longo, que dura aproximadamente 10 minutos.

Após 5 minutos, eu gostaria de executar um comando separado. Para ilustração, o comando separado pode ser:echo 5 minutes complete

(Nota: não quero avançar para a conclusão do comando, mas simplesmente comandos executados após intervalos especificados.)

É possível?

Aniket Bhattacharyea
fonte
1
Na maioria das vezes, você não sabe com antecedência quanto tempo levará um processo.
choroba 28/05
O que você quer dizer com "comandos baseados no tempo"? Deseja criar uma barra de progresso? Com base na formulação atual da sua pergunta, você pode simplesmente colocar o comando de execução longa em segundo plano e exibir o relógio do sistema. Por favor, esclareça.
Curinga
@ Wildcard eu esclareci na pergunta. Não é uma barra de progresso. Ele irá executar comandos após alguns intervalos
Aniket Bhattacharyea
1
"5 minutos completos" é uma coisa estranha de se repetir. Ainda não se passaram "5 minutos"? Não é "A hora é _____"? Deseja apenas garantir que algum intervalo de tempo especificado tenha decorrido desde o início do comando de longa duração, antes da execução de outro comando arbitrário? Se sim, por que não apenas correr longcommand & sleep 300 && command-to-do-after-five-minutes? (Na verdade, é provavelmente o que você está procurando.) Observe que seu esclarecimento não foi suficiente, pois você conseguiu duas implementações de barra de progresso do relógio logo de cara.
Curinga

Respostas:

29

Apenas corra:

long-command & sleep 300; do-this-after-five-minutes

A do-this-after-five-minutescorrida será executada após cinco minutos. O long-commandserá executado em segundo plano.

Curinga
fonte
10
Eu costumo usar sleep 5m && foobar, então se eu mudar de idéia e ^ C o sleep, o próximo comando não será executado.
Peter Cordes
@ PeterCordes, quando eu testei com eg sleep 3; lse ^C, o segundo comando não é executado de qualquer maneira. Não sabe ao certo por que e talvez funcione de maneira diferente em um shell não interativo?
Curinga
1
@ PeterCordes Não é bem assim - a menos que seja diferente por shell. Quando sleep 5m && echoestá em suspensão, quando você suspende, apenas o sleepcomando está suspenso. O restante da linha de comando é executado, mas desde que sleepfoi suspenso, ele não foi encerrado com êxito e a parte após &&foi ignorada. Tente suspender sleep 5 || echo helloe helloapareça diretamente após pressionar ^Z.
hvd 29/05
1
@hvd: Sim, você está certo, e eu estou errado de novo>. <, usando o bash4. Aparentemente, faz muito tempo desde que eu decidi que o && era o caminho a seguir como gueto at(1), para coisas como sleep 30m && mplayer something.mp3lembrete de alarme ou para sleep 90m && fgretomar um comando com uso intensivo de disco mais tarde. Então, na verdade, sleep 5m && echo helloé bom porque ^Zsuspende sleepsem executar o seguinte comando. Se você deseja suspender / retomar todo o comando composto, mesmo antes de o sono terminar, use ( sleep 2 && echo hello ).
Peter Cordes
@ DVD: O &&idioma permite que você tenha certeza absoluta de que não interrompe o processo logo após a suspensão (porque você pode ^Znão executar o comando, em vez de arriscar a ^C). Isso é útil no caso de uso sleep && fgou sleep && bg, quando o comando que está sendo retomado é parcialmente lento.
Peter Cordes
5

Você pode usar este script:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

Ele executa o seu longprocessem um sub-shelle monitora o arquivo 'lock' criado anteriormente para existência.

Sarja
fonte
2
Verifique se man bashSECONDS. Você pode definir SECONDS=0no início roteiro e só verificar se há maior ou igual a 300 ou conjunto SECONDS=$((date +%s))e esquecer utilizando datenovamente em seu script ...
@ yeti, obrigado pela dica, eu não sabia disso.
Serge
@ yeti, se você quiser confiar no tempo depois de sleep 1ssempre ter exatamente um segundo depois do que era antes sleep 1s... então você foi vítima das falsidades que os programadores acreditam sobre o tempo . (Embora neste caso, você pode também mostrar uma barra de progresso de marca de hash ou algo assim.) #
Wildcard
@Wildcard ... eu não mencionei sleepnada!
@ yeti, você está certo. Obrigado pela dica sobre SECONDS! :)
Curinga
4

Existe um liner para isso:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

No seu caso, TIMEOUT = 5m e COMMAND é o comando longo.

Veja também minha resposta a este post Tempo limite com 'reinicialização da rede de serviço'

coffeMug
fonte
Iniciar um subshell em primeiro plano e depois executar o comando parece desnecessariamente complicado. Eu removeria os parênteses externos e o exec.
Glenn Jackman
1
@glennjackman Desta forma, é possível eliminar todo o procedimento enviando CTRL + C (por exemplo) para o sub-shell principal (mais externo).
2828 de
1
Mas, usando exec, você não tem mais um subshell, apenas o comando. O pai do comando é o shell que executa o script como se você não tivesse usado um subshell.
Glenn Jackman
3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 falha quando o trabalho% 1 é interrompido.

Observe que, por períodos mais longos, $ segundos podem ficar fora de sincronia com o tempo real. É melhor armazenar a hora de início e calcular a diferença para a hora real.

choroba
fonte