Ripetere un comando ogni x intervallo di tempo nel terminale?


143

Come posso ripetere un comando ogni intervallo di tempo, in modo che mi consenta di eseguire comandi per controllare o monitorare le directory?

Non è necessario uno script, ho solo bisogno di un semplice comando da eseguire nel terminale.

Risposte:


220

È possibile utilizzare il watchcomando, watch viene utilizzato per eseguire qualsiasi comando designato a intervalli regolari.

Apri Terminale e digita:

watch -n x <your command>

cambia x per essere il tempo in secondi che desideri.

Per ulteriori informazioni sull'uso del watchcomando e delle sue opzioni, esegui man watcho visita questo link .

Ad esempio: di seguito verranno elencati, ogni 60s , sullo stesso Terminale, i contenuti della directory Desktop in modo da poter sapere se sono state apportate modifiche:

watch -n 60 ls -l ~/Desktop

34
+1 ma fai attenzione quando usi le espansioni. Ad esempio, prova la differenza tra watch -n 1 'echo $COLUMNS'e watch -n 1 echo $COLUMNSquando ridimensiona il tuo terminale: il primo viene espanso ogni secondo, ma il secondo viene espanso solo una volta prima dell'inizio watch .
l0b0

Esso funziona magicamente ! Ty nux

Il problema che ho con questa soluzione è che non puoi eseguire watch come processo e lasciarlo in esecuzione in background (ad esempio con &
disown

2
Esiste un modo per utilizzare watchcon il comando di tipo "cronologia abilitata"? Adoro usare watch, ma a volte preferirei vedere anche un registro delle precedenti esecuzioni, anziché solo l'ultima. E sì, lo so che posso usare scripting ( while true) per ottenere questo risultato, ma usare l' watchutilità è molto più pulito!
Rinogo,

questo ha funzionato per comandi più semplici ma con i comandi pipeline concatenati non ha funzionato per me. Di seguito è stato il comando che ho provato => cat api.log | grep 'chiamando' | wc -l
Sudip Bhandari,

90

Puoi anche usare questo comando nel terminale, a parte la risposta di nux:

while true; do <your_command>; sleep <interval_in_seconds>; done

Esempio

while true; do ls; sleep 2; done

Questo comando stampa l'output lsa un intervallo di 2 sec.

Usa Ctrl+ Cper interrompere il processo.

Ci sono alcuni svantaggi di watch

  • Non può utilizzare alcun comando con alias.
  • Se l'output di qualsiasi comando è piuttosto lungo, lo scorrimento non funziona correttamente.
  • Vi sono alcuni problemi nell'impostare l'intervallo di tempo massimo oltre un determinato valore.
  • watchinterpreterà le sequenze di colori ANSI passando i caratteri di escape usando -co l' --coloropzione. Ad esempio, l'output di pygmentizefunzionerà ma non funzionerà ls --color=auto.

Nelle circostanze di cui sopra ciò può apparire come un'opzione migliore.


watchesiste per questo, è un po 'inutile direi
Bruno Pereira,

14
Non sto affermando che questa risposta debba essere utilizzata al primo posto. watchè buono nella maggior parte dei casi. Questo è il motivo per cui ho citato "a parte la risposta di nux" all'inizio. Ma ci sono alcuni problemi con, watchad esempio, non è possibile utilizzare alcun comando con aliaswatch . Prendiamo ad esempio ciò llche è alias ls -laFma con il quale non può essere utilizzato watch. Inoltre, nel caso in cui l'output di un comando sia piuttosto lungo, avrai problemi a scorrere usando watch. In questi pochi casi speciali questa risposta può apparire un'opzione migliore.
souravc,

@souravc La mia versione di watchalmeno consente le opzioni -co --colorper l'output colorato.
Lily Chung

8
while sleep xè meglio - è più facile uccidere.
d33tah,

3
Questa è una buona alternativa e, a differenza watch, mantiene la cronologia dei comandi.
adelriosantiago,

34

Volevo solo presentare le risposte di souravc e nux :

  1. Mentre watchfunzionerà perfettamente su Ubuntu, potresti voler evitare che se vuoi che il tuo "Unix-fu" sia puro - su FreeBSD per esempio, watch è un comando per "curiosare su un'altra linea tty".
  2. while true; do command; sleep SECONDS; doneha anche un avvertimento - il vostro comando potrebbe essere più difficili da uccidere utilizzando CTR + C . Potresti voler preferire while sleep SECONDS; do command; done: non è solo più breve, ma anche più facile da interrompere. L'avvertenza è che prima dormirà, quindi eseguirà il tuo comando, quindi dovrai aspettare alcuni SECONDSprima che accada la prima occorrenza del comando.

2
Spero che sia accettabile come una risposta invece di un commento: volevo mostrare un'altra soluzione qui e commentare mi avrebbe effettivamente prestato meno attenzione.
d33tah,

Perché importa esattamente dove ti metti sleepnel whileloop? Non sono riuscito a trovare alcuna differenza, Ctrl + C ha interrotto immediatamente il ciclo, non importa quale.
dessert,

@dessert: dipende da cosa stai provando a sfuggire, suppongo. Normalmente, Ctrl + C sarebbe solo uccidere il vostro commanded sleepe rompere solo se si uccide true.
d33tah,

11

Sembra il compito ideale per il crondemone che consente di eseguire comandi periodici. Esegui il crontab -ecomando per iniziare a modificare la configurazione cron dell'utente. Il suo formato è documentato in crontab (5) . Fondamentalmente hai cinque campi relativi al tempo, separati dallo spazio, seguiti da un comando:

The time and date fields are:

       field          allowed values
       -----          --------------
       minute         0-59
       hour           0-23
       day of month   1-31
       month          1-12 (or names, see below)
       day of week    0-7 (0 or 7 is Sunday, or use names)

Ad esempio, se desideri eseguire uno script Python ogni martedì, alle 11.00:

0 11 * * 1 python ~/yourscript.py

Ci sono anche alcuni nomi speciali che sostituiscono il tempo, come @reboot. Molto utile se è necessario creare una directory temporanea. Dal mio crontab (elencato con crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"

4
La domanda chiede come eseguire periodicamente qualcosa nel terminale. croncorre dietro le quinte piuttosto che nel terminal
bradley settentrionale

5

Se stai monitorando il file system, allora inotifywaitè geniale e sicuramente aggiunge meno carico al tuo sistema.

Esempio :

Nel 1 ° terminale digitare questo comando:

$ inotifywait .

Quindi nel 2 ° terminale, qualsiasi comando che influisce sulla directory corrente,

$ touch newfile

Quindi nel terminale originale inotifywait si sveglia e segnala l'evento

./ CREATE newfile2

O in un ciclo

$ while true ; do inotifywait . ; done
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ DELETE newfile
Setting up watches.  
Watches established.
./ CREATE,ISDIR newdir
Setting up watches.  
Watches established.

l'utente te lo ha detto, nessuno script, e forse non vuole monitorare nulla
nux

3
Non gli ho detto di scrivere una sceneggiatura, gli ho suggerito che se stanno eseguendo un ciclo in ordine per controllare un determinato evento del filesystem, allora inotifywait è utile e usa meno risorse rispetto alla ripetizione di un comando. Spesso eseguo diversi comandi su una riga di comando, ad esempio grep something InALogFile|lessè uno script?
X Tian

è una buona risposta, prova a modificarlo per sembrare più semplice.
nux

3
Cosa potrebbe esserci di più semplice di .non poter tralasciare il comando.
X Tian

Grazie @XTian, ​​un ottimo comando. Ho anche visto nella pagina man che è possibile aggiungere -mper monitorare continuamente senza loop.
yoniLavi,

4

È possibile creare il proprio repeatcomando procedendo come segue; crediti qui :

Innanzitutto, apri il tuo .bash_aliasesfile:

$ xdg-open ~/.bash-aliases

In secondo luogo, incolla queste righe nella parte inferiore del file e salva:

repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
    "$@"
done
}

Terzo, chiudi e riapri il tuo terminale o digita:

$ source ~/.bash_aliases

Et voilà ! Ora puoi usarlo in questo modo:

$ repeat 5 echo Hello World !!!

o

$ repeat 5 ./myscript.sh

c'è un piccolo errore di battitura nella riga xdg-open ~ / .bash-aliases. dovrebbe essere: xdg-open ~ / .bash_aliases (es .: underscore)
ssinfod

4

puoi usare crontab. esegui il comando crontab -ee aprilo con il tuo editor di testo preferito, quindi aggiungi questa riga

*/10 * * * *  /path-to-your-command

Questo eseguirà il tuo comando ogni 10 minuti

* */4 * * *  /path-to-your-command

Questo eseguirà il tuo comando ogni 4 ore

Un'altra possibile soluzione

$ ..some command...; for i in $(seq X); do $cmd; sleep Y; done

X numero di volte da ripetere.

Y tempo di aspettare per ripetere.

Esempio :

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done

Perché questo è un miglioramento? Hai appena aggiunto un passaggio aggiuntivo, inutile, salvando il comando come variabile. L'unica cosa che fa è: i) allungare il tempo a digitare ii) ti costringe a usare solo comandi semplici, niente pipe o reindirizzamenti ecc.
terdon

Rimuovi la variabile aggiuntiva
Maythux

3

Un'altra preoccupazione con l'approccio "watch" proposto sopra è che mostra il risultato solo quando il processo è terminato. "date; sleep 58; date" visualizzerà le 2 date solo dopo 59 secondi ... Se avvii qualcosa in esecuzione per 4 minuti, che visualizzano lentamente più pagine di contenuto, non lo vedrai davvero.

D'altra parte, la preoccupazione con l'approccio "while" è che non prende in considerazione la durata dell'attività.

while true; do script_that_take_between_10s_to_50s.sh; sleep 50; done

Con questo, lo script verrà eseguito ogni minuto, a volte potrebbe richiedere 1m40. Quindi, anche se un cron sarà in grado di eseguirlo ogni minuto, qui non lo farà.

Quindi, per vedere l'output sulla shell mentre viene generato e attendere il tempo esatto della richiesta, è necessario guardare l'ora prima e dopo e fare un ciclo con il while.

Qualcosa di simile a:

while ( true ); do
  echo Date starting `date`
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))`
  echo Before waiting `date`
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
  echo Done waiting `date`
done

Questo produrrà questo:

Come puoi vedere, il comando viene eseguito ogni minuto:

Date starting Mon Dec 14 15:49:34 EST 2015
Before waiting Mon Dec 14 15:49:52 EST 2015
Done waiting Mon Dec 14 15:50:34 EST 2015

Date starting Mon Dec 14 15:50:34 EST 2015
Before waiting Mon Dec 14 15:50:39 EST 2015
Done waiting Mon Dec 14 15:51:34 EST 2015

Quindi sostituisci semplicemente il echo $(( ( RANDOM % 30 ) + 1 ))comando "sleep " con quello che vuoi e che verrà eseguito, sul terminale / shell, esattamente ogni minuto. Se vuoi un altro programma, cambia i "60" secondi con quello che ti serve.

Versione più breve senza le righe di debug:

while ( true ); do
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))` # Place you command here
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
done

Rispondere a me stesso ... Se il tuo comando richiede più del ritardo che configuri, $ DELAY otterrà un valore negativo e il comando sleep fallirà, quindi lo script si riavvierà immediatamente. Devo esserne consapevole.
jmspaggi,
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.