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.