Répéter une commande tous les x intervalles de temps dans le terminal?

143

Comment répéter une commande à chaque intervalle de temps pour pouvoir exécuter des commandes de vérification ou de surveillance des répertoires?

Il n'y a pas besoin d'un script, j'ai juste besoin d'une simple commande à exécuter dans un terminal.

muru
la source

Réponses:

220

Vous pouvez utiliser watchcommande, watch est utilisé pour exécuter toute commande désignée à intervalles réguliers.

Ouvrez le terminal et tapez:

watch -n x <your command>

changez x pour être le temps en secondes que vous voulez.

Pour obtenir de l'aide supplémentaire sur l'utilisation de la watchcommande et de ses options, exécutez man watchou visitez ce lien .

Par exemple: ce qui suit va lister, toutes les 60 secondes , sur le même terminal, le contenu du répertoire Desktop afin que vous puissiez savoir si des modifications ont eu lieu:

watch -n 60 ls -l ~/Desktop
nux
la source
34
+1 mais soyez prudent lorsque vous utilisez des extensions. Par exemple, essayez de faire la différence entre watch -n 1 'echo $COLUMNS'et watch -n 1 echo $COLUMNSlors du redimensionnement de votre terminal: le premier est développé toutes les secondes, mais le dernier n’est développé qu’une fois avant le watch début.
l0b0
Il fonctionne comme un charme ! Ty nux
Le problème que j'ai avec cette solution est que vous ne pouvez pas lancer watch en tant que processus et le laisser fonctionner en arrière-plan (par exemple, avec & désavouer)
Cestarian
2
Est-il possible d'utiliser watchavec une commande de type "historique activé"? J'aime utiliser watch, mais parfois je préférerais voir un journal des exécutions précédentes aussi bien que juste la dernière. Et oui, je sais que je peux utiliser un script ( while true) pour accomplir cela, mais l’ watchutilitaire est beaucoup plus propre!
rinogo
cela fonctionnait pour des commandes plus simples mais avec des commandes en pipeline enchaînées, cela ne fonctionnait pas pour moi. grep 'appelle' | wc -l
Sudip Bhandari
90

Vous pouvez également utiliser cette commande dans terminal, en dehors de la réponse de nux:

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

Exemple

while true; do ls; sleep 2; done

Cette commande affichera la sortie tous les ls2 secondes.

Utilisez Ctrl+ Cpour arrêter le processus.

Il y a peu d'inconvénients de watch

  • Il ne peut utiliser aucune commande avec alias.
  • Si le résultat d'une commande est assez long, le défilement ne fonctionne pas correctement.
  • Il est difficile de définir un intervalle de temps maximal au- delà d'une certaine valeur.
  • watchinterprétera les séquences de couleurs ANSI en transmettant les caractères d'échappement à l'aide de l' option -cou --color. Par exemple, la sortie de pygmentizetravaillera mais échouera pour ls --color=auto.

Dans les circonstances ci-dessus, cela peut sembler une meilleure option.

souravc
la source
watchexiste pour cela, c'est un peu inutile je dirais
Bruno Pereira
14
Je ne prétends pas que cette réponse doit être utilisée en premier lieu. watchest bon dans la plupart des cas. C'est pourquoi j'ai mentionné "en dehors de la réponse de Nux" au début. Mais il y a peu de problèmes avec watchpar exemple On ne peut utiliser aucune commande avec aliaswatch . Prenons l'exemple de l' llalias qui ls -laFne peut être utilisé avec watch. De même, si le résultat d’une commande est assez long, vous aurez du mal à faire défiler avec watch. Dans ces quelques cas particuliers, cette réponse peut sembler une meilleure option.
Souravc
@souravc Ma version d' watchau moins autorise les options -cou --colorpour une sortie colorisée.
Lily Chung
8
while sleep xc'est mieux - c'est plus facile à tuer.
d33tah
3
C'est une bonne alternative et, contrairement à watchcela, elle conserve l'historique des commandes.
Adelriosantiago
34

Je voulais juste apporter ma réponse aux réponses de souravc et nux :

  1. Bien que watchcela fonctionne parfaitement sur Ubuntu, vous voudrez peut-être éviter cela si vous voulez que votre "Unix-fu" soit pur - sur FreeBSD par exemple, watch est une commande pour "espionner sur une autre ligne de tty".
  2. while true; do command; sleep SECONDS; donea aussi une mise en garde - votre commande pourrait être plus difficile à tuer en utilisant CTR + C . Vous voudrez peut-être préférer while sleep SECONDS; do command; done- c'est non seulement plus court, mais aussi plus facile à interrompre. La mise en garde est qu'il va d'abord dormir, puis exécuter votre commande, vous devrez donc attendre SECONDSavant que la première occurrence de la commande se produise.
d33tah
la source
2
J'espère que c'est acceptable comme réponse plutôt que comme commentaire - je voulais montrer une autre solution ici et commenter m'attirerait moins d'attention.
d33tah
Pourquoi exactement où vous mettez sleepdans la whileboucle? Je ne trouvais aucune différence, Ctrl + C rompait instantanément la boucle, peu importe quoi.
Dessert
@dessert: cela dépend de ce que vous essayez d'éclater, je suppose. Normalement, ctrl + c tuerait simplement votre commandet sleepet ne casserait que si vous le tuiez true.
d33tah
11

Cela semble être la tâche idéale du crondémon, qui permet d’exécuter des commandes périodiques. Exécutez la crontab -ecommande pour commencer à modifier la configuration cron de votre utilisateur. Son format est documenté dans crontab (5) . En gros, vous avez cinq champs liés au temps, séparés par des espaces, suivis d'une commande:

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)

Par exemple, si vous souhaitez exécuter un script Python tous les mardis, 11 heures:

0 11 * * 1 python ~/yourscript.py

Il y a aussi des noms spéciaux qui remplacent l'heure, comme @reboot. Très utile si vous devez créer un répertoire temporaire. De ma crontab (listée avec crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"
Lekensteyn
la source
4
La question demande comment exécuter quelque chose périodiquement dans le terminal. cronse passe dans les coulisses plutôt que dans le terminal
northern-bradley
5

Si vous surveillez le système de fichiers, il inotifywaitest brillant et ajoute certainement moins de charge sur votre système.

Exemple :

Au 1er terminal tapez cette commande:

$ inotifywait .

Ensuite, dans 2nd terminal, toute commande qui affecte le répertoire en cours,

$ touch newfile

Puis inotifywait dans le terminal d'origine se réveille et rapporte l'événement

./ CREATE newfile2

Ou en boucle

$ 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.
X Tian
la source
l'utilisateur vous a dit, pas de script, et peut-être qu'il ne veut rien surveiller
nux
3
Je ne lui ai pas dit d'écrire un script, je lui ai suggéré que si ils bouclent pour surveiller un événement de système de fichiers particulier, inotifywait est utile et utilise moins de ressources que de répéter une commande. J'exécute souvent plusieurs commandes sur une ligne de commande, par exemple, grep something InALogFile|lesss'agit-il d'un script?
X Tian
C'est une bonne réponse, essayez de le modifier pour qu'il soit plus simple.
Nux
3
Ce qui pourrait être plus simple que .je ne peux pas laisser de côté la commande.
X Tian
Merci @XTian, ​​une excellente commande. J'ai également vu dans la page de manuel que vous pouvez ajouter -mpour surveiller en continu sans boucle.
yoniLavi
4

Vous pouvez créer votre propre repeatcommande en procédant comme suit: crédits ici :

Commencez par ouvrir votre .bash_aliasesfichier:

$ xdg-open ~/.bash-aliases

Deuxièmement, collez ces lignes au bas du fichier et enregistrez:

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

Troisièmement, fermez et rouvrez votre terminal ou tapez:

$ source ~/.bash_aliases

Et voilà ! Vous pouvez maintenant l'utiliser comme ceci:

$ repeat 5 echo Hello World !!!

ou

$ repeat 5 ./myscript.sh
Blufter
la source
il y a une petite faute de frappe dans la ligne xdg-open ~ / .bash-aliases. ce devrait être: xdg-open ~ / .bash_aliases (par exemple: underscore)
ssinfod
4

vous pouvez utiliser crontab. lancez la commande crontab -eet ouvrez-la avec votre éditeur de texte préféré, puis ajoutez cette ligne

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

Cela lancera votre commande toutes les 10 minutes

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

Cela exécutera votre commande toutes les 4 heures

Une autre solution possible

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

X nombre de fois à répéter.

Y le temps d'attendre pour répéter.

Exemple :

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done
Maythux
la source
Pourquoi est-ce une amélioration? Vous venez d'ajouter une étape supplémentaire inutile en enregistrant la commande en tant que variable. La seule chose que cela fait, c’est que i) rende le temps plus long pour taper ii) vous oblige à n’utiliser que des commandes simples, pas de tuyaux, ni de redirections, etc.
terdon
Supprimer la variable supplémentaire
Maythux
3

L’approche «veille» proposée ci-dessus pose un autre problème: elle n’affiche le résultat que lorsque le processus est terminé. "date; sommeil 58; date" affichera les 2 dates seulement après 59 secondes ... Si vous démarrez quelque chose pendant 4 minutes, si vous affichez lentement plusieurs pages de contenu, vous ne le verrez pas vraiment.

D'autre part, le problème avec l'approche "tant que" est qu'elle ne prend pas en compte la durée de la tâche.

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

Avec cela, le script s'exécutera toutes les minutes, parfois 1m40. Donc même si un cron sera capable de le lancer toutes les minutes, ici, il ne le fera pas.

Donc, pour voir la sortie sur le shell telle qu'elle est générée et attendre l'heure exacte de la requête, vous devez regarder l'heure avant et après et boucler avec.

Quelque chose comme:

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

Cela produira ceci:

Comme vous pouvez le constater, la commande s’exécute toutes les minutes:

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

Il suffit donc de remplacer la echo $(( ( RANDOM % 30 ) + 1 ))commande "sleep " par ce que vous voulez et qui sera exécutée, sur le terminal / shell, exactement chaque minute. Si vous voulez un autre horaire, il suffit de changer les "60" secondes avec tout ce dont vous avez besoin.

Version plus courte sans les lignes de débogage:

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
jmspaggi
la source
Répondre à moi-même ... Si votre commande prend plus que le délai que vous configurez, $ DELAY aura une valeur négative et la commande sleep échouera, le script redémarrera immédiatement. Besoin d'être conscient de cela.
Jmspaggi