Ich möchte eine schnelle und einfache Möglichkeit, einen Befehl auszuführen, wenn sich eine Datei ändert. Ich möchte etwas sehr Einfaches, etwas, das ich auf einem Terminal laufen lassen und schließen werde, wenn ich mit der Arbeit an dieser Datei fertig bin.
Derzeit verwende ich Folgendes:
while read; do ./myfile.py ; done
Und dann muss ich zu diesem Terminal gehen und drücken Enter, wann immer ich diese Datei in meinem Editor speichere. Was ich will, ist ungefähr so:
while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done
Oder irgendeine andere Lösung, die so einfach ist.
Übrigens: Ich verwende Vim und weiß, dass ich einen automatischen Befehl hinzufügen kann, um etwas auf BufWrite auszuführen, aber dies ist nicht die Art von Lösung, die ich jetzt möchte.
Update: Ich möchte etwas einfaches, wenn möglich wegwerfbares. Außerdem möchte ich, dass etwas in einem Terminal ausgeführt wird, weil ich die Programmausgabe sehen möchte (ich möchte Fehlermeldungen sehen).
Über die Antworten: Danke für all deine Antworten! Sie sind alle sehr gut und gehen alle ganz anders vor als die anderen. Da ich nur eines akzeptieren muss, akzeptiere ich das, das ich tatsächlich verwendet habe (es war einfach, schnell und leicht zu merken), obwohl ich weiß, dass es nicht das eleganteste ist.
Antworten:
Einfach mit inotifywait (Installiere das
inotify-tools
Paket deiner Distribution ):oder
Das erste Snippet ist einfacher, hat jedoch einen erheblichen Nachteil: Es werden Änderungen übersehen, die ausgeführt werden, während
inotifywait
es nicht ausgeführt wird (insbesondere, währendmyfile
es ausgeführt wird). Das zweite Snippet hat diesen Defekt nicht. Beachten Sie jedoch, dass der Dateiname kein Leerzeichen enthält. Wenn dies ein Problem ist, verwenden Sie die--format
Option, um die Ausgabe so zu ändern, dass der Dateiname nicht mehr enthalten ist:In beiden Fällen gibt es eine Einschränkung: Wenn ein Programm
myfile.py
durch eine andere Datei ersetzt, anstatt in die vorhandene zu schreibenmyfile
,inotifywait
stirbt es. Viele Redakteure arbeiten so.Verwenden Sie
inotifywait
für das Verzeichnis Folgendes, um diese Einschränkung zu umgehen:Verwenden Sie alternativ ein anderes Tool, das dieselbe zugrunde liegende Funktionalität verwendet, z. B. incron (mit dem Sie Ereignisse registrieren können, wenn eine Datei geändert wird) oder fswatch (ein Tool, das auch für viele andere Unix-Varianten unter Verwendung der Analoga jeder Variante von Linux inotify funktioniert).
quelle
sleep_until_modified.sh
Skript, abrufbar unter: bitbucket.org/denilsonsa/small_scripts/srcwhile sleep_until_modified.sh derivation.tex ; do latexmk -pdf derivation.tex ; done
ist fantastisch. Danke.inotifywait -e delete_self
scheint für mich gut zu funktionieren.while inotifywait -e close_write myfile.py; do ./myfile.py; done
immer beendet, ohne den Befehl auszuführen (bash und zsh). Damit dies funktioniert, musste ich zum|| true
Beispielwhile inotifywait -e close_write myfile.py || true; do ./myfile.py; done
entr ( http://entrproject.org/ ) bietet eine benutzerfreundlichere Oberfläche zum Inotifizieren (und unterstützt auch * BSD und Mac OS X).
Es macht es sehr einfach, mehrere zu überwachende Dateien anzugeben (nur begrenzt durch
ulimit -n
), erleichtert den Umgang mit zu ersetzenden Dateien und erfordert weniger Bash-Syntax:Ich habe es in meinem gesamten Projektquellbaum verwendet, um die Komponententests für den Code auszuführen, den ich gerade ändere, und es hat meinen Workflow bereits enorm verbessert.
Flags wie
-c
(Löschen des Bildschirms zwischen den Durchläufen) und-d
(Beenden, wenn eine neue Datei zu einem überwachten Verzeichnis hinzugefügt wird) bieten noch mehr Flexibilität. Sie können beispielsweise Folgendes tun:Ab Anfang 2018 befindet es sich noch in der aktiven Entwicklung und ist in Debian & Ubuntu (
apt install entr
) zu finden. Das Bauen aus dem Repo des Autors war auf jeden Fall schmerzfrei.quelle
-d
Flagge; Es ist etwas langatmiger, aber Sie könnenwhile sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
mit neuen Dateien umgehen.brew install entr
wird es wie erwartetIch schrieb ein Python - Programm zu tun genau dies genannt , wenn-verändert .
Die Verwendung ist einfach:
Oder um mehrere Dateien anzusehen:
FILE
kann ein Verzeichnis sein. Beobachten Sie rekursiv mit-r
. Verwenden Sie%f
diese Option , um den Dateinamen an den Befehl zu übergeben.quelle
when-changed FILE 'clear; COMMAND'
.when-changed
ist jetzt plattformübergreifend! Schauen Sie sich die neueste Version 0.3.0 an :)Wie wäre es mit diesem Skript? Er verwendet den
stat
Befehl, um die Zugriffszeit einer Datei abzurufen, und führt einen Befehl aus, wenn sich die Zugriffszeit ändert (wenn auf eine Datei zugegriffen wird).quelle
stat
die geänderte Zeit nicht eine bessere Antwort, wenn sich eine Datei ändert?vmstat -d
nach Festplattenzugriffen Ausschau gehalten. Es scheint, dass Linux einen fantastischen Job beimLösung mit Vim:
Aber ich möchte diese Lösung nicht, weil es etwas nervig ist, etwas zu tippen, es ist ein bisschen schwierig, sich genau zu merken, was zu tippen ist, und es ist ein bisschen schwierig, seine Effekte rückgängig zu machen (müssen ausgeführt werden
:au! BufWritePost myfile.py
). Außerdem blockiert diese Lösung Vim, bis der Befehl ausgeführt wurde.Ich habe diese Lösung hier nur der Vollständigkeit halber hinzugefügt, da sie anderen Leuten helfen könnte.
Entfernen Sie den
:silent
Befehl , um die Programmausgabe anzuzeigen (und Ihren Bearbeitungsablauf vollständig zu unterbrechen, da die Ausgabe einige Sekunden lang über Ihren Editor schreibt, bis Sie die Eingabetaste drücken) .quelle
entr
(siehe unten) ganz nett sein - lassen Sie vim einfach eine Dummy-Datei berühren, die entr gerade betrachtet, und den Rest im Hintergrund erledigen ... odertmux send-keys
wenn Sie sich in einer solchen Umgebung befinden :).vimrc
Datei erstellenWenn Sie zufällig
npm
installiert haben,nodemon
ist dies wahrscheinlich der einfachste Weg, um loszulegen, insbesondere unter OS X, das anscheinend keine inotify-Tools hat. Es unterstützt das Ausführen eines Befehls, wenn sich ein Ordner ändert.quelle
nodemon -x "bundle exec rspec" spec/models/model_spec.rb -w app/models -w spec/models
WatchPaths
Schlüssel verwenden, wie in meinem Link gezeigt.Für diejenigen, die nicht
inotify-tools
wie ich installieren können , sollte dies nützlich sein:watch -d -t -g ls -lR
Dieser Befehl wird beendet, wenn sich die Ausgabe ändert. Er
ls -lR
listet alle Dateien und Verzeichnisse mit Größe und Datum auf. Wenn also eine Datei geändert wird, sollte er den Befehl beenden, wie man sagt:Ich weiß, dass diese Antwort von niemandem gelesen werden kann, aber ich hoffe, dass jemand darauf eingehen würde.
Befehlszeilenbeispiel:
Öffnen Sie ein anderes Terminal:
Nun wird das erste Terminal ausgegeben
1,2,3
Einfaches Skript-Beispiel:
quelle
watch -d -t -g "ls -lR tmp | sha1sum"
watch from procps-ng 3.3.10
) akzeptiert Float-Sekunden als Intervall und fragt daherwatch -n0.2 ...
jede fünfte Sekunde ab. Gut für gesunde Tests in Einheiten unter einer Millisekunde.rerun2
( on github ) ist ein 10- zeiliges Bash-Skript der Form:Speichern Sie die Github-Version als 'Rerun' auf Ihrem PATH und rufen Sie sie auf mit:
Es wird BEFEHL jedes Mal ausgeführt, wenn sich ein Dateisystemänderungsereignis in Ihrem aktuellen Verzeichnis befindet (rekursiv).
Dinge, die man daran mögen könnte:
Dinge, die man daran nicht mögen könnte:
Dies ist eine Verfeinerung von @ cychois Antwort.
quelle
"$@"
statt verwenden$@
, um ordnungsgemäß mit Argumenten zu arbeiten, die Leerzeichen enthalten. Gleichzeitig verwenden Sie jedocheval
, was den Benutzer von Rerun dazu zwingt, beim Zitieren besonders vorsichtig zu sein.rerun 'command'
. Sind Sie nur sagen , dass , wenn ich „$ @“ verwendet, dann könnte der Benutzer aufrufen , wiererun command
die nicht so nützlich für mich scheint (ohne Anführungszeichen?): Ich in der Regel nicht wollen , Bash zu tun , jede Verarbeitung des Befehls , bevor es vorbei zu wiederholen. Wenn der Befehl zB "echo $ myvar" enthält, möchte ich die neuen Werte von myvar in jeder Iteration sehen.rerun foo "Some File"
könnte zerbrechen. Aber da Sie verwendeneval
, kann es als umgeschrieben werdenrerun 'foo "Some File"
. Beachten Sie, dass bei der Pfaderweiterung manchmal Leerzeichen eingefügt werden:rerun touch *.foo
Diese werden wahrscheinlich unterbrochen, und bei der Verwendungrerun 'touch *.foo'
wird eine geringfügig andere Semantik verwendet (die Pfaderweiterung erfolgt nur einmal oder mehrmals).rerun ls "some file"
bricht wegen der Leerzeichen.rerun touch *.foo*
Funktioniert normalerweise einwandfrei, schlägt jedoch fehl, wenn die mit * .foo übereinstimmenden Dateinamen Leerzeichen enthalten. Vielen Dank, dass Sie mir dabei geholfen haben, herauszufinden, wiererun 'touch *.foo'
unterschiedliche Semantiken vorliegen, aber ich vermute, dass die Version mit einfachen Anführungszeichen die von mir gewünschte Semantik ist: Ich möchte, dass jede Wiederholungsiteration so funktioniert, als ob ich den Befehl erneut eingetippt hätte - daher möchte*.foo
ich sie bei jeder Iteration erweitern . Ich werde Ihre Vorschläge versuchen, um ihre Auswirkungen zu untersuchen ...Hier ist ein einfaches Shell-Bourne-Shell-Skript, das:
Bereinigt sich selbst, wenn Sie Strg-C drücken
Dies funktioniert unter FreeBSD. Das einzige Portabilitätsproblem, an das ich denken kann, ist, wenn ein anderes Unix den Befehl mktemp (1) nicht hat, aber in diesem Fall können Sie den Namen der temporären Datei einfach hart codieren.
quelle
$cmd
, aber glücklicherweise ist dies leicht zu beheben: Lassen Sie diecmd
Variable los und führen Sie sie aus"$@"
. Ihr Skript ist nicht für die Überwachung einer großen Datei geeignet. Dies kann jedoch durch Ersetzencp
durch behoben werdentouch -r
(Sie benötigen nur das Datum, nicht den Inhalt). Portabilitätstechnisch-nt
erfordert der Test bash, ksh oder zsh.Werfen Sie einen Blick auf Incron . Es ist ähnlich wie cron, verwendet jedoch inotify-Ereignisse anstelle von time.
quelle
Eine andere Lösung mit NodeJs, fsmonitor :
Installieren
Über die Befehlszeile (Beispiel: Überwachen von Protokollen und "Einzelhandel", wenn sich eine Protokolldatei ändert)
quelle
tail -F -q *.log
, denke ich.tail -f
nichtclear
das Terminal.Sehen Sie sich Guard an, insbesondere mit diesem Plugin:
https://github.com/hawx/guard-shell
Sie können es so einrichten, dass es eine beliebige Anzahl von Mustern im Verzeichnis Ihres Projekts überwacht und Befehle ausführt, wenn Änderungen auftreten. Gute Chancen, auch wenn es ein Plugin gibt, das genau das tut, was Sie versuchen.
quelle
Wenn Sie Nodemon installiert haben, können Sie dies tun:
In meinem Fall bearbeite ich HTML lokal und versende es an meinen Remote-Server, wenn sich eine Datei ändert.
quelle
Unter Linux:
Führt den Befehl alle 2 Sekunden aus.
Wenn Ihr Befehl länger als 2 Sekunden dauert, wartet watch, bis er ausgeführt wurde, bevor es erneut ausgeführt wird.
quelle
Watchdog ist ein Python-Projekt und könnte genau das sein, wonach Sie suchen:
Habe gerade einen Kommandozeilen-Wrapper dafür geschrieben
watchdog_exec
:Beispiel läuft
Führen Sie bei einem fs-Ereignis mit Dateien und Ordnern im aktuellen Verzeichnis den
echo $src $dst
Befehl aus, sofern das fs-Ereignis nicht geändert wurde, und führen Sie dann denpython $src
Befehl aus.Verwenden Sie kurze Argumente und beschränken Sie sich darauf, nur ausgeführt zu werden, wenn Ereignisse " main .py" beinhalten:
BEARBEITEN: Gerade gefunden Watchdog hat eine offizielle CLI angerufen
watchmedo
, also checkt das auch aus.quelle
Wenn Ihr Programm eine Art Protokoll / Ausgabe generiert, können Sie ein Makefile mit einer Regel für dieses Protokoll / diese Ausgabe erstellen, die von Ihrem Skript abhängt und etwas Ähnliches bewirkt
Alternativ können Sie ein Phony-Ziel erstellen und die Regel dafür festlegen, dass sowohl Ihr Skript aufgerufen wird als auch das Phony-Ziel berührt wird (obwohl dies immer noch von Ihrem Skript abhängt).
quelle
while sleep 1 ; do something ; done
ist etwas besser alswhile true ; do something ; sleep 1 ; done
. Zumindest stoppt es leicht, wenn Sie Strg + C drücken.swarminglogic hat ein Skript namens watchfile.sh geschrieben , das auch als GitHub Gist verfügbar ist .
quelle
stat
das die angegebenen Dateinamen abfragt, inmd5sum
der Ausgabe ausgeführt und den angegebenen Befehl erneut ausführt, wenn sich dieser Wert ändert. Da es sich um Bash handelt, ist es meiner Meinung nach eine gute Aufgabe, den angegebenen Befehl so auszuführen, als ob Sie ihn an einer Bash-Eingabeaufforderung eingegeben hätten. (Im Gegensatz dazu können die meisten der hier in anderen Sprachen geschriebenen Lösungen keine Befehle ausführen, die beispielsweise Shell-Aliase enthalten wiell
)Gilles 'Antwort wurde verbessert .
Diese Version wird
inotifywait
einmal ausgeführt und überwacht anschließend Ereignisse (z. B.modify
). Diesinotifywait
muss nicht bei jedem aufgetretenen Ereignis erneut ausgeführt werden.Es geht schnell und schnell! (Auch wenn große Verzeichnisse rekursiv überwacht werden)
quelle
Ein bisschen mehr auf der Programmierseite, aber Sie möchten so etwas wie inotify . Es gibt Implementierungen in vielen Sprachen, z. B. jnotify und pyinotify .
Mit dieser Bibliothek können Sie einzelne Dateien oder ganze Verzeichnisse überwachen und Ereignisse zurückgeben, wenn eine Aktion erkannt wird. Die zurückgegebenen Informationen umfassen unter anderem den Dateinamen, die Aktion (Erstellen, Ändern, Umbenennen, Löschen) und den Dateipfad.
quelle
Für diejenigen unter Ihnen, die eine FreeBSD-Lösung suchen, ist hier der Port:
quelle
Ich mag die Einfachheit,
while inotifywait ...; do ...; done
aber es gibt zwei Probleme:do ...;
, werden übersehenAus diesem Grund habe ich ein Hilfsskript erstellt , das inotifywait ohne diese Einschränkungen verwendet: inotifyexec
Ich schlage vor, dass Sie dieses Skript in Ihren Pfad einfügen, wie in
~/bin/
. Die Verwendung wird nur durch Ausführen des Befehls beschrieben.Beispiel:
inotifyexec "echo test" -r .
quelle
Verbesserte Sebastian-Lösung mit
watch
Befehl:watch_cmd.sh
:Aufrufbeispiel:
Es funktioniert, aber seien Sie vorsichtig: Der
watch
Befehl hat bekannte Fehler (siehe man): Er reagiert nur auf Änderungen in VISIBLE in Terminal-Teilen der-g CMD
Ausgabe.quelle
Du könntest es mit Reflex versuchen .
Reflex ist ein kleines Tool, mit dem Sie ein Verzeichnis überwachen und einen Befehl erneut ausführen können, wenn sich bestimmte Dateien ändern. Es eignet sich hervorragend zum automatischen Ausführen von Kompilierungs- / Flusen- / Testaufgaben und zum erneuten Laden Ihrer Anwendung, wenn sich der Code ändert.
quelle
Eine Online-Antwort, mit der ich eine Dateiänderung nachverfolge:
Sie müssen BF nicht initialisieren, wenn Sie wissen, dass das erste Datum die Startzeit ist.
Das ist einfach und portabel. Es gibt eine andere Antwort, die auf der gleichen Strategie basiert und hier ein Skript verwendet. Schauen Sie auch mal rein.
Verwendung: Ich benutze dies, um Fehler zu beheben und ein Auge darauf zu haben
~/.kde/share/config/plasma-desktop-appletsrc
. dass aus irgendeinem unbekannten Grund meine immer wieder verliertSwitchTabsOnHover=false
quelle
Ich benutze dieses Skript, um es zu tun. Ich benutze inotify im Monitor-Modus
Speichern Sie dies als runatwrite.sh
Bei jedem Schreibvorgang wird myfile.sh ausgeführt.
quelle
Für Benutzer von OS X können Sie einen LaunchAgent verwenden, um einen Pfad / eine Datei auf Änderungen zu überwachen und in diesem Fall Maßnahmen zu ergreifen. FYI - LaunchControl ist eine gute App zum einfachen Erstellen / Ändern / Entfernen von Daemons / Agents.
( Beispiel von hier genommen )
quelle
Ich habe ein GIST dafür und die Verwendung ist ziemlich einfach
https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55
quelle
Für Leute, die dies durch Googeln nach Änderungen an einer bestimmten Datei finden, ist die Antwort viel einfacher (inspiriert von Gilles 'Antwort ).
Wenn Sie etwas tun möchten, nachdem in eine bestimmte Datei geschrieben wurde, gehen Sie wie folgt vor:
Speichern Sie dies beispielsweise als
copy_myfile.sh
und legen Sie die.sh
Datei in den/etc/init.d/
Ordner, damit sie beim Start ausgeführt wird.quelle
Das 'Fido'-Tool könnte eine weitere Option für diesen Bedarf sein. Siehe https://www.joedog.org/fido-home/
quelle
Wie einige andere bereits geschrieben haben, habe ich auch ein einfaches Befehlszeilentool geschrieben, um dies zu tun. Es ist vollständig dokumentiert, getestet und modular.
Watch-Do
Installation
Du kannst es installieren (wenn du Python3 und pip hast) mit:
Verwendungszweck
Verwenden Sie es sofort, indem Sie Folgendes ausführen:
Funktionsübersicht
-w '*.py'
oder-w '**/*.py'
)-d
Flag erneut an)-r
um dies zu aktivieren )quelle