Esegui il comando ogni X secondi


10

Vorrei eseguire un comando ogni 10 secondi e farlo eseguire in background (eliminando così watch?). Tutte le risposte mostrano qualcosa di simile al seguente, ma questo verrà eseguito da 11 a 14 secondi. Come può essere realizzato?

while true; do
    # perform command that takes between 1 and 4 seconds
    sleep 10
done

forse con segnali in tempo reale. e corretta gestione dei secondi bisestili. in bocca al lupo.
Mikeserv,

@mikeserv Quindi, non preoccuparti di provare? Non mi interessa l'accuratezza di un millesimo di secondo, dì solo mezzo secondo.
user1032531

Cosa stai cercando di realizzare? Trovo che un'attività che deve essere eseguita con quel tipo di frequenza sia di solito una soluzione alternativa per un altro problema.
Sobrique,

@Sobrique Esatto. Sto facendo una prova del concetto di un registratore di dati di polling. In realtà, sarà programmato in un'altra lingua, ma per ora funziona.
user1032531,

Risposte:


16

Che ne dite di:

( # In a subshell, for isolation, protecting $!
  while true; do
    perform-command & # in the background
    sleep 10 ;
    ### If you want to wait for a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line:
    # wait $! ;
    ### If you prefer to kill a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line instead:
    # kill $! ;
    ### (If you prefer to ignore it, uncomment neither.)
  done
)

ETA: con tutti quei commenti, alternative e la subshell per una protezione aggiuntiva, sembra molto più complicato di quanto sia iniziato. Quindi, per confronto, ecco come appariva prima che iniziassi a preoccuparmi waito kill, con il loro $!e il bisogno di isolamento:

while true; do perform-command & sleep 10 ; done

Il resto è davvero solo per quando ne hai bisogno.


Puoi spiegare il ragionamento alla base del tuo dump del codice?
Ismael Miguel,

2
Inoltre, per citare per quale shell funziona il tuo codice (come la risposta di Mikeserv) in modo che le persone non si confondano quando una shell diversa si comporta diversamente :)
ash

@IsmaelMiguel Ho pensato che i commenti avrebbero spiegato il ragionamento. Non sono sicuro di cosa non sia chiaro.
Il Sidhekin l'

1
Il manuale di bash dice $!: "Si espande nell'ID processo del lavoro posizionato più recentemente in background" e sleepnon viene inserito in background, quindi no, non lo farà. :)
The Sidhekin,

1
Wow. sbagliato su entrambi i fronti. quando è successo?
Mikeserv,

9

Si può fare qualcosa di simile a quanto segue in bash, zsho ksh:

SECONDS=0
while   command
do      sleep "$((10-(SECONDS%10)))"
done

Ecco cosa bashdice il manuale su $SECONDS:

$SECONDS

  • Ogni volta che si fa riferimento a questo parametro, viene restituito il numero di secondi dall'invocazione della shell. Se viene assegnato un valore $SECONDS, il valore restituito nei riferimenti successivi è il numero di secondi dall'assegnazione più il valore assegnato. Se $SECONDSè unset, perde le sue proprietà speciali, anche se è poi ripristinato.

Ecco un esempio funzionante:

(   SECONDS=0
    while   sleep   "$((RANDOM%10))"
    do      sleep   "$((10-(SECONDS%10)))"
            echo    "$SECONDS"
    done
)

10
20
30
40
50
60
70
80
90
100

2
Per evitare il ripristino, SECONDSfare sleep "$((10-(($SECONDS-$start_time)%10)))". Dovrai fare start_time=$SECONDSprima del loop.
ctrl-alt-delor,

@richard - perché evitarlo?
Mikeserv,

perché un giorno lo avrai in uno script che chiami con in un tale ciclo. E passerai tutto il giorno a chiederti perché non funziona correttamente. In breve, non si annida, se ripristinato SECONDS. Generare una sotto-shell come nella tua ultima modifica, dovrebbe anche evitare questo problema.
ctrl-alt-delor,

1
@richard - dato che la domanda riguardava un while trueloop non immaginavo che uno stato della shell potesse sopravvivere. Avvolgere un loop del genere nel suo contesto è di solito la migliore pratica, comunque. In una situazione del genere, però, sarei più preoccupato di farlo per trapil bene che per $SECONDSil bene.
Mikeserv,

Grazie Mike, stavo pensando di fare qualcosa di simile (ma non sapevo ancora i dettagli come). Ma la soluzione di Sidhekin sembra fare la stessa cosa, no? Non sono qualificato per giudicare la risposta migliore, ma mi sono sentito obbligato a scegliere qualcosa.
user1032531

3

Solo BASH: puoi anche calcolare il tempo impiegato dal tuo comando e sottrarre da 10:

TIMEFORMAT=$'%0R'
while true; do
    T=$({ time command; } 2>&1)
    sleep $(( 10-T ))

Dall'uomo BASH:

TIMEFORMAT Il valore di questo parametro viene utilizzato come stringa di formato che specifica come devono essere visualizzate le informazioni di temporizzazione per le pipeline con il prefisso con la parola con tempo riservato. Il carattere% introduce una sequenza di escape che viene espansa in un valore temporale o altre informazioni. Le sequenze di escape e i loro significati sono i seguenti; le parentesi graffe indicano porzioni opzionali.
%% Una% letterale.
% [p] [l] R Il tempo trascorso in secondi.
% [p] [l] U Il numero di secondi CPU spesi in modalità utente.
% [p] [l] S Il numero di secondi CPU spesi in modalità di sistema.
% P La percentuale di CPU, calcolata come (% U +% S) /% R.

La p opzionale è una cifra che specifica la precisione, il numero di cifre frazionarie dopo un punto decimale. Un valore pari a 0 non genera alcun punto decimale o frazione.

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.