Eseguire il comando dopo che è trascorso un certo periodo di tempo?


24

Se sto eseguendo un lungo processo, c'è un modo per eseguire alcuni comandi basati sul tempo?

Ad esempio, sto eseguendo un processo davvero lungo che dura circa 10 minuti.

Dopo 5 minuti, vorrei eseguire un comando separato. A titolo illustrativo, il comando separato potrebbe essere:echo 5 minutes complete

(Nota: non voglio avanzare verso il completamento del comando, ma semplicemente comandi eseguiti dopo intervalli specificati.)

È possibile?


1
Il più delle volte, non sai in anticipo quanto tempo impiegherà un processo.
Choroba,

Cosa intendi per "comandi basati sul tempo"? Vuoi creare una barra di avanzamento? In base all'attuale formulazione della tua domanda, potresti semplicemente mettere in background il comando long running e quindi visualizzare l'orologio di sistema. Si prega di precisare.
Wildcard

@Wildcard Ho chiarito la domanda. Non una barra di avanzamento. Eseguirà i comandi dopo alcuni intervalli
Aniket Bhattacharyea,

1
"5 minuti completi" è una cosa strana da echeggiare. Non sono trascorsi 5 minuti? Non "Il tempo è _____"? Vuoi solo assicurarti che sia trascorso un determinato intervallo di tempo dal momento in cui è stato avviato il tuo comando di lunga durata, prima che venga eseguito un altro comando arbitrario? Se è così, perché non correre longcommand & sleep 300 && command-to-do-after-five-minutes? (In realtà è probabilmente quello che stai cercando.) Nota che il tuo chiarimento non è stato sufficiente, dato che hai subito due implementazioni con barra di avanzamento dell'orologio.
Wildcard

Risposte:


29

Corri:

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

Il do-this-after-five-minutesotterrà eseguito dopo cinque minuti. Il long-commandsarà in esecuzione in background.


10
Di solito lo uso sleep 5m && foobar, quindi se cambio idea e ^ C il sleep, il comando successivo non viene eseguito.
Peter Cordes,

@PeterCordes, quando l'ho provato con eg sleep 3; lse ^C, il secondo comando non viene eseguito comunque. Non sai perché e forse funziona diversamente in una shell non interattiva?
Wildcard

1
@PeterCordes Non del tutto, a meno che non differisca per shell. Quando sleep 5m && echodorme, quando sospendi, sleepviene sospeso solo il comando. Il resto della riga di comando viene eseguito, ma poiché è sleepstato sospeso, non è stato chiuso correttamente e la parte successiva &&viene ignorata. Prova a sospendere sleep 5 || echo helloe si hellopresenta direttamente dopo aver premuto ^Z.
hvd,

1
@hvd: Sì, hai ragione, e mi sbaglio di nuovo>. <, usando bash4. Apparentemente è passato troppo tempo da quando ho deciso che && era la strada da percorrere come ghetto at(1), per cose come sleep 30m && mplayer something.mp3promemoria di allarme o per sleep 90m && fgriprendere un comando intensivo del disco in seguito. Quindi, in realtà, sleep 5m && echo helloè bello perché ^Zsospende sleepsenza eseguire il seguente comando. Se vuoi essere in grado di sospendere / riprendere l'intero comando composto, anche prima che finisca il sonno, usa ( sleep 2 && echo hello ).
Peter Cordes,

@hvd: il &&linguaggio ti consente di essere assolutamente sicuro di non interrompere il processo subito dopo l' esecuzione del sonno (perché non puoi ^Zeseguire il comando, invece di rischiare a ^C). Ciò è utile nel caso d'uso sleep && fgo sleep && bg, quando il comando che viene ripreso è in parte attraverso qualcosa di lento.
Peter Cordes,

5

Puoi usare questo 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!!!"

Esegue il tuo longprocessin a sub-shelle quindi controlla l'esistenza del file 'lock' precedentemente creato.


2
Controlla man bashper SECONDS. Puoi impostare SECONDS=0all'avvio dello script e verificare solo un valore maggiore o uguale a 300 o impostare SECONDS=$((date +%s))e dimenticare di dateriutilizzarlo nello script ...

@yeti, grazie per il suggerimento, non lo sapevo.
Serge,

@yeti, se vuoi fare affidamento sul tempo dopo sleep 1sessere sempre stato esattamente un secondo dopo rispetto a prima sleep 1s... allora sei caduto vittima di Falsehood che i programmatori credono nel tempo . (Anche se in questo caso, potresti anche solo mostrare una barra di avanzamento del segno di hash o qualcosa del genere.)
Wildcard

@Wildcard ... non ho menzionato sleepaffatto!

@yeti, hai ragione. Grazie per il suggerimento in merito SECONDS! :)
Wildcard

4

C'è una sola fodera per questo:

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

Nel tuo caso TIMEOUT = 5m e COMMAND è il comando lungo.

Vedi anche la mia risposta a questo post Timeout con "riavvio della rete di servizio"


Il lancio di una subshell in primo piano e quindi l'esecuzione del comando sembrano inutilmente complicati. Vorrei rimuovere le parentesi esterne e il exec.
Glenn Jackman,

1
@glennjackman In questo modo è possibile terminare l'intera procedura inviando CTRL + C (ad esempio) alla sotto-shell principale (più esterna).
coffeMug

1
Ma usando exec, non hai più una subshell, hai solo il comando. Il genitore del comando è la shell che esegue lo script proprio come se non avessi usato affatto una 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 ha esito negativo una volta arrestato il processo% 1.

Nota che per periodi più lunghi, $ secondi potrebbero non essere sincronizzati con il tempo reale. È meglio memorizzare l'ora di inizio e calcolare la differenza rispetto all'ora effettiva.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.