Befehl alle x Zeitintervalle im Terminal wiederholen?

142

Wie kann ich einen Befehl jedes Mal wiederholen , damit ich Befehle zum Überprüfen oder Überwachen von Verzeichnissen ausführen kann ?

Es wird kein Skript benötigt, ich brauche nur einen einfachen Befehl, um im Terminal ausgeführt zu werden.

muru
quelle

Antworten:

219

Sie können watchbefehl verwenden. Watch wird verwendet, um einen bestimmten Befehl in regelmäßigen Abständen auszuführen.

Öffnen Sie das Terminal und geben Sie Folgendes ein:

watch -n x <your command>

Ändern Sie x , um die gewünschte Zeit in Sekunden anzugeben.

Wenn Sie weitere Hilfe zur Verwendung des watchBefehls und seiner Optionen benötigen, führen man watchSie diesen Link aus oder besuchen Sie ihn .

Beispiel: Die folgende Liste listet alle 60 Sekunden auf demselben Terminal den Inhalt des Desktop-Verzeichnisses auf, damit Sie wissen, ob Änderungen vorgenommen wurden:

watch -n 60 ls -l ~/Desktop
nux
quelle
34
+1 aber seien Sie vorsichtig, wenn Sie Erweiterungen verwenden. Probieren Sie zum Beispiel den Unterschied zwischen watch -n 1 'echo $COLUMNS'und aus, watch -n 1 echo $COLUMNSwenn Sie die Größe Ihres Terminals ändern - das erste wird jede Sekunde erweitert, das zweite wird jedoch nur einmal erweitert, bevor es watch gestartet wird.
l0b0
Es wirkt wie ein Zauber ! Ty nux
Das Problem, das ich mit dieser Lösung habe, ist, dass Sie watch nicht als Prozess ausführen können und es einfach im Hintergrund laufen lassen (zum Beispiel mit & disown)
Cestarian
2
Gibt es eine Möglichkeit, den watchBefehl vom Typ "history enabled" zu verwenden? Ich benutze es sehr gerne watch, aber manchmal würde ich es vorziehen, auch ein Protokoll früherer Hinrichtungen zu sehen, anstatt nur das letzte. Und ja, ich weiß, dass ich Scripting ( while true) verwenden kann, um dies zu erreichen, aber die Verwendung des watchDienstprogramms ist so viel sauberer!
Rinogo
Dies funktionierte für einfachere Befehle, aber mit verketteten Befehlen funktionierte dies nicht für mich. Das Folgende war der Befehl, den ich ausprobierte => cat api.log | grep 'aufrufen' | wc -l
Sudip Bhandari
90

Sie können diesen Befehl auch im Terminal verwenden, abgesehen von der Antwort von nux:

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

Beispiel

while true; do ls; sleep 2; done

Dieser Befehl druckt die Ausgabe lsim Abstand von 2 Sekunden.

Mit Ctrl+ Cbeenden Sie den Vorgang.

Es gibt einige Nachteile von watch

  • Es können keine Alias-Befehle verwendet werden.
  • Wenn die Ausgabe eines Befehls ziemlich lang ist, funktioniert das Scrollen nicht richtig.
  • Es gibt einige Probleme, das maximale Zeitintervall über einen bestimmten Wert hinaus einzustellen .
  • watchinterpretiert ANSI-Farbsequenzen, die Escape-Zeichen mit der Option -coder übergeben --color. Zum Beispiel wird die Ausgabe von pygmentizefunktionieren, aber es wird fehlschlagen ls --color=auto.

Unter den oben genannten Umständen kann dies als bessere Option erscheinen.

souravc
quelle
watchgibt es dafür, das ist ein bisschen nutzlos würde ich sagen
Bruno Pereira
14
Ich behaupte nicht, dass diese Antwort an erster Stelle verwendet werden soll. watchist in den meisten Fällen gut. Deshalb habe ich am Anfang "abgesehen von der Antwort von nux" erwähnt. Es gibt aber nur wenige Probleme mit watchzum Beispiel Man kann keine mit Alias ​​versehenen Befehle mit verwendenwatch . Nehmen wir zum Beispiel lldas, was voreingenommen ist, ls -laFaber nicht verwendet werden kann watch. Auch für den Fall, dass die Ausgabe eines Befehls sehr lang ist, können Sie beim Scrollen mit Schwierigkeiten haben watch. In diesen wenigen Sonderfällen scheint diese Antwort eine bessere Option zu sein.
Souravc
@souravc In meiner Version von sind watchmindestens die Optionen -coder --colorfür die farbige Ausgabe zulässig .
Lily Chung
8
while sleep xist besser - es ist einfacher zu töten.
8.
3
Dies ist eine nette Alternative und watchbehält im Gegensatz dazu den Befehlsverlauf bei.
Adelriosantiago
34

Ich wollte nur auf die Antworten von souravc und nux eingehen :

  1. Während watches unter Ubuntu perfekt funktioniert, möchten Sie vielleicht vermeiden, dass Ihr "Unix-fu" rein ist - unter FreeBSD ist watch beispielsweise ein Befehl, um "in einer anderen tty-Zeile zu suchen".
  2. while true; do command; sleep SECONDS; donehat auch eine Einschränkung - Ihr Befehl ist möglicherweise schwieriger mit STRG + C zu töten . Vielleicht möchten Sie es vorziehen while sleep SECONDS; do command; done- es ist nicht nur kürzer, sondern auch leichter zu unterbrechen. Die Einschränkung besteht darin, dass zuerst der Ruhezustand aktiviert und dann SECONDSder Befehl ausgeführt wird. Daher müssen Sie einige Sekunden warten, bis der Befehl zum ersten Mal ausgeführt wird.
d33tah
quelle
2
Ich hoffe, es ist akzeptabel als Antwort anstelle eines Kommentars - ich wollte hier eine andere Lösung zeigen und das Kommentieren würde mir tatsächlich weniger Aufmerksamkeit schenken.
d33tah
Warum genau ist es wichtig, wo Sie sleepin die whileSchleife setzen? Ich konnte keinen Unterschied feststellen. Strg + C hat die Schleife sofort unterbrochen, egal was passiert.
Dessert
@dessert: Kommt darauf an, woraus du auszubrechen versuchst, denke ich. Normalerweise würde Strg + C nur Ihr commandund töten sleepund nur brechen, wenn Sie töten true.
d33tah
11

Klingt nach einer idealen Aufgabe für den cronDaemon, bei der periodische Befehle ausgeführt werden können. Führen Sie den crontab -eBefehl aus, um die Cron-Konfiguration Ihres Benutzers zu bearbeiten. Das Format ist in crontab (5) dokumentiert . Grundsätzlich haben Sie fünf zeitbezogene, durch Leerzeichen getrennte Felder, gefolgt von einem Befehl:

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)

Wenn Sie beispielsweise jeden Dienstag um 11:00 Uhr ein Python-Skript ausführen möchten:

0 11 * * 1 python ~/yourscript.py

Es gibt auch einige spezielle Namen, die die Zeit ersetzen, wie z @reboot. Sehr hilfreich, wenn Sie ein temporäres Verzeichnis erstellen müssen. Aus meiner Crontab (gelistet mit crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"
Lekensteyn
quelle
4
Bei der Frage wird gefragt, wie etwas im Terminal regelmäßig ausgeführt werden soll. cronläuft eher hinter die
kulissen
5

Wenn Sie das Dateisystem überwachen, inotifywaitist dies brillant und belastet Ihr System mit Sicherheit weniger.

Beispiel

Im ersten Terminal geben Sie diesen Befehl ein:

$ inotifywait .

Dann in 2. Terminal, jeder Befehl, der das aktuelle Verzeichnis betrifft,

$ touch newfile

Dann wird in dem ursprünglichen Terminal inotifywait aufwachen und das Ereignis melden

./ CREATE newfile2

Oder in einer Schleife

$ 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
quelle
der benutzer hat dir gesagt, kein script, und vielleicht will er gar nichts überwachen
nux
3
Ich habe ihm nicht gesagt, dass er ein Skript schreiben soll, und ich habe vorgeschlagen, dass inotifywait nützlich ist, wenn sie eine Schleife ausführen, um nach bestimmten Dateisystemereignissen zu suchen, und weniger Ressourcen verbraucht als das Wiederholen eines Befehls. Ich führe oft mehrere Befehle in einer Befehlszeile aus, zB grep something InALogFile|lessist das ein Skript?
X Tian
Es ist eine gute Antwort, versuchen Sie es zu bearbeiten, um einfacher auszusehen.
Nux
3
Was könnte einfacher sein, als .ich den Befehl nicht auslassen kann.
X Tian
Danke @XTian, ​​ein großartiger Befehl. Ich habe jetzt auch in der Manpage gesehen, dass man -mohne Schleife kontinuierlich überwachen kann .
YoniLavi
4

Sie können Ihren eigenen repeatBefehl erstellen, indem Sie die folgenden Schritte ausführen: Credits hier :

Öffnen Sie zuerst Ihre .bash_aliasesDatei:

$ xdg-open ~/.bash-aliases

Fügen Sie als zweites diese Zeilen am Ende der Datei ein und speichern Sie:

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

Drittens können Sie entweder Ihr Terminal schließen und wieder öffnen oder Folgendes eingeben:

$ source ~/.bash_aliases

Et voilà! Du kannst es jetzt so benutzen:

$ repeat 5 echo Hello World !!!

oder

$ repeat 5 ./myscript.sh
Blufter
quelle
In der Zeile xdg-open ~ / .bash-aliases befindet sich ein kleiner Tippfehler. Es sollte sein: xdg-open ~ / .bash_aliases (dh: Unterstrich)
ssinfod
4

Sie können Crontab verwenden. Führen Sie den Befehl aus crontab -eund öffnen Sie ihn mit Ihrem bevorzugten Texteditor. Fügen Sie dann diese Zeile hinzu

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

Dadurch wird Ihr Befehl alle 10 Minuten ausgeführt

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

Dadurch wird Ihr Befehl alle 4 Stunden ausgeführt

Eine andere mögliche Lösung

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

X Anzahl der Wiederholungen.

Y Zeit zu warten, um zu wiederholen.

Beispiel

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done
Maythux
quelle
Warum ist das eine Verbesserung? Sie haben gerade einen zusätzlichen, unnötigen Schritt hinzugefügt, indem Sie den Befehl als Variable gespeichert haben. Das einzige, was dies bewirkt, ist, dass Sie i) die Eingabe verlängern müssen ii) nur einfache Befehle verwenden müssen, keine Pipes oder Weiterleitungen usw.
terdon
Entfernen Sie die zusätzliche Variable
Maythux
3

Ein weiteres Problem bei dem oben vorgeschlagenen "Watch" -Ansatz besteht darin, dass das Ergebnis nur angezeigt wird, wenn der Vorgang abgeschlossen ist. "date; sleep 58; date" zeigt die 2 Daten erst nach 59 Sekunden an ... Wenn Sie etwas starten, das 4 Minuten läuft und langsam mehrere Seiten mit Inhalten anzeigt, werden Sie es nicht wirklich sehen.

Auf der anderen Seite besteht das Problem beim "while" -Ansatz darin, dass die Aufgabendauer nicht berücksichtigt wird.

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

Mit diesem Befehl wird das Skript einmal alle Minuten ausgeführt, manchmal dauert es 1: 40 Minuten. Selbst wenn ein Cron es alle Minuten ausführen kann, ist dies hier nicht der Fall.

Um die Ausgabe auf der Shell zu sehen, während sie generiert wird, und auf die genaue Anforderungszeit zu warten, müssen Sie die Zeit davor und danach betrachten und eine Schleife mit der while-Anweisung durchführen.

So etwas wie:

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

Dies gibt Folgendes aus:

Wie Sie sehen, wird der Befehl alle Minuten ausgeführt:

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

Ersetzen Sie also einfach den echo $(( ( RANDOM % 30 ) + 1 ))Befehl "sleep " durch einen beliebigen Befehl, der auf dem Terminal / der Shell genau jede Minute ausgeführt wird. Wenn Sie einen anderen Zeitplan wünschen, ändern Sie einfach die "60" Sekunden nach Bedarf.

Kürzere Version ohne die Debug-Zeilen:

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
quelle
Antworten an mich selbst ... Wenn Ihr Befehl länger dauert als die von Ihnen konfigurierte Verzögerung, erhält $ DELAY einen negativen Wert und der Befehl sleep schlägt fehl, sodass das Skript sofort neu gestartet wird. Muss mir dessen bewusst sein.
jmspaggi