Gibt es auf dem Mac einen Befehl wie "watch" oder "inotifywait"?


287

Ich möchte einen Ordner auf meinem Mac (Snow Leopard) ansehen und dann ein Skript ausführen (mit dem Dateinamen dessen, was gerade in einen Ordner verschoben wurde (als Parameter ... x.sh "Dateiname")).

Ich habe ein Skript, das alle in bash (x.sh) geschrieben ist und einige Dateien und andere Dinge bei Eingabe von $ 1 verschiebt. Ich brauche nur OSX, um mir den Dateinamen zu geben, wenn neue Dateien / Ordner in ein Verzeichnis verschoben / erstellt werden.

Irgendein solcher Befehl?


1
Sie sollten sich fragen, wie DropBox das macht, da sie vermutlich alle verfügbaren Optionen ausprobiert haben.
Jeff Burdges

2
@ JeffBurdges Ich bin mir nicht sicher, ob das ein einfaches Unterfangen wäre. Ich würde jedoch sagen, dass es nach dem Überfliegen von Apples FSEvents-Referenz wirklich albern wäre, wenn Dropbox dies nicht nutzen würde. Das fswatchunten als Antwort dargestellte util verwendet tatsächlich diese Methode.
Steven Lu

Antworten:


446

fswatch

fswatch ist ein kleines Programm, das die Mac OS X FSEvents-API zum Überwachen eines Verzeichnisses verwendet. Wenn ein Ereignis über eine Änderung in diesem Verzeichnis empfangen wird, wird der angegebene Shell-Befehl von ausgeführt/bin/bash

Wenn Sie mit GNU / Linux arbeiten, bietet inotifywatch (Teil des inotify-toolsPakets bei den meisten Distributionen) ähnliche Funktionen.

Update: fswatch Kann jetzt auf vielen Plattformen verwendet werden, einschließlich BSD, Debian und Windows.

Syntax / Ein einfaches Beispiel

Die neue Methode, mit der mehrere Pfade überwacht werden können - für Versionen 1.x und höher :

fswatch -o ~/path/to/watch | xargs -n1 -I{} ~/script/to/run/when/files/change.sh

Hinweis: Die von ausgegebene Nummer -owird am Ende des xargsBefehls hinzugefügt, wenn nicht für -I{}. Wenn Sie diese Nummer verwenden möchten, platzieren Sie sie an einer {}beliebigen Stelle in Ihrem Befehl.

Der ältere Weg für Versionen 0.x :

fswatch ~/path/to/watch ~/script/to/run/when/files/change.sh

Installation mit Homebrew

Ab dem 12.9.13 wurde es wieder zu Homebrew hinzugefügt - yay! Aktualisieren Sie also Ihre Formelliste ( brew update) und alles, was Sie tun müssen, ist:

brew install fswatch

Installation ohne Homebrew

Geben Sie diese Befehle ein Terminal.app

cd /tmp
git clone https://github.com/alandipert/fswatch
cd fswatch/
make
cp fswatch /usr/local/bin/fswatch

Wenn Sie keinen cCompiler auf Ihrem System haben, müssen Sie möglicherweise Xcode- oder Xcode-Befehlszeilentools installieren - beide kostenlos. Wenn dies jedoch der Fall ist, sollten Sie sich wahrscheinlich nur Homebrew ansehen .

Zusätzliche Optionen für fswatchVersion 1.x.

Usage:
fswatch [OPTION] ... path ...

Options:
 -0, --print0          Use the ASCII NUL character (0) as line separator.
 -1, --one-event       Exit fsw after the first set of events is received.
 -e, --exclude=REGEX   Exclude paths matching REGEX.
 -E, --extended        Use exended regular expressions.
 -f, --format-time     Print the event time using the specified format.
 -h, --help            Show this message.
 -i, --insensitive     Use case insensitive regular expressions.
 -k, --kqueue          Use the kqueue monitor.
 -l, --latency=DOUBLE  Set the latency.
 -L, --follow-links    Follow symbolic links.
 -n, --numeric         Print a numeric event mask.
 -o, --one-per-batch   Print a single message with the number of change events.
                       in the current batch.
 -p, --poll            Use the poll monitor.
 -r, --recursive       Recurse subdirectories.
 -t, --timestamp       Print the event timestamp.
 -u, --utc-time        Print the event time as UTC time.
 -v, --verbose         Print verbose output.
 -x, --event-flags     Print the event flags.

See the man page for more information.

Ihre Anweisungen oder die Installation ohne Homebrew scheinen nicht mehr zu funktionieren. makelöst einen Fehler aus, wenn kein Makefile gefunden wird. Glücklicherweise ist fswatch jetzt auf MacPorts verfügbar und sudo port install fswatchfunktioniert auch für diejenigen von uns, die MacPorts anstelle von Homebrew verwenden.
Coredumperror

Wenn Sie einen Befehl mit statischen Argumenten verwenden (z. B. habe ich meine Komponententests auf src und Teständerungen ausgeführt), funktioniert dies möglicherweise nicht für Sie. Diese Frage ( stackoverflow.com/questions/25689589/… ) war das zweite Stück, das ich brauchte.
Jskulski

4
Ich höre dich da draußen:fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
Fionbio

fswatch ist besser als Tools wie entr oder when_changed, die beim Umgang mit dem .git-Verzeichnis einige Fehler aufweisen. fswatch ist viel professioneller. Sie fswatch .überwachen einfach das aktuelle Verzeichnis.
anonym

Ich würde fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]mit -0für NULL vorschlagen. Dieser arbeitet für mich für weniger Zusammenstellung
boldnik

95

Zu diesem Zweck können Sie launchd verwenden. Launchd kann so konfiguriert werden, dass ein Programm automatisch gestartet wird, wenn ein Dateipfad geändert wird.

Beispielsweise startet die folgende Startkonfigurationsliste das Programm, /usr/bin/loggerwenn der Desktop-Ordner meines Benutzerkontos geändert wird:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>logger</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/logger</string>
        <string>path modified</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/sakra/Desktop/</string>
    </array>
</dict>
</plist>

Um die Konfigurationsliste zu aktivieren, speichern Sie sie im Ordner LaunchAgents in Ihrem Bibliotheksordner als "logger.plist".

In der Shell können Sie dann mit dem Befehl launchctldie Datei logger.plist aktivieren, indem Sie Folgendes ausführen:

$ launchctl load ~/Library/LaunchAgents/logger.plist

Der Desktop-Ordner wird jetzt überwacht. Jedes Mal, wenn es geändert wird, sollte eine Ausgabe in der Datei system.log angezeigt werden (verwenden Sie Console.app). Führen Sie Folgendes aus, um die Datei logger.plist zu deaktivieren:

$ launchctl unload ~/Library/LaunchAgents/logger.plist

Die obige Konfigurationsdatei verwendet die WatchPathsOption. Alternativ können Sie auch die QueueDirectoriesOption verwenden. Weitere Informationen finden Sie in der Manpage launchd .


1
Gibt es eine Möglichkeit, die Änderung des Dateiinhalts sowie des Dateipfads zu überwachen?
Cam

2
Das glaube ich nicht. Zu diesem Zweck können Sie opensnoop verwenden.
Sakra

1
Ich habe das zum Laufen gebracht, aber als ich dann /usr/bin/loggermit meinem Bash-Skript wechselte und den "<string>path modified</strong>"Eintrag entfernte, konnte ich für mein Bash-Skript keine Möglichkeit finden, zu wissen, welche Datei auf meinem Desktop geändert wurde - nur, dass das Ereignis aufgetreten ist. Ich habe versucht , Blick auf $0, $1und bekam nur den Namen des Skripts selbst und merkt an sie übergeben.
Volomike

Geht dieses Ding auch in eine Schleife, sobald es eine Änderung erkennt, anstatt nur zu starten (und anzuhalten), wenn es eine Änderung erkennt? Ich möchte lieber, dass es auf Abruf funktioniert und nicht in einer Schleife läuft, die mir mitteilt, dass sich beispielsweise vor zwei Tagen etwas auf meinem Desktop geändert hat, und dies immer wieder in das Protokoll schreibt. Müssen wir also eine Art Intervalloption in dieser Liste verwenden?
Volomike

Großartige Arbeit und
Erklärung

37

Der über Homebrew erhältliche Facebook- Wächter sieht ebenfalls gut aus. Es unterstützt auch das Filtern:

Diese beiden Zeilen richten eine Überwachung in einem Quellverzeichnis ein und richten dann einen Trigger mit dem Namen "buildme" ein, der bei jeder Änderung einer CSS-Datei ein Tool mit dem Namen "minify-css" ausführt. Dem Tool wird eine Liste der geänderten Dateinamen übergeben.

$ watchman watch ~/src

$ watchman -- trigger ~/src buildme '*.css' -- minify-css

Beachten Sie, dass der Pfad absolut sein muss.


1
Dies ist bei weitem das beste Werkzeug.
BentOnCoding

1
Dies ist ein sehr schönes kleines Programm: Die Dokumente sind großartig, es öffnet keine Endlosschleife (was fswatch zu tun scheint) und es merkt sich die Uhren, die Sie nach dem Neustart erstellt haben, und startet sie automatisch neu.
Brad

21

Vielleicht möchten Sie sich mein kleines Tool ansehen (und es vielleicht erweitern) kqwait. Derzeit sitzt es nur herum und wartet auf ein Schreibereignis in einer einzelnen Datei, aber die Kqueue- Architektur ermöglicht das hierarchische Stapeln von Ereignissen ...


Funktioniert bisher auf Berglöwen. Sehr schön!
Scott

Das ist wirklich großartig. Ich bin auf ein kleines Problem gestoßen fswatch(was auch in Ordnung ist, da es ein so leichter Wrapper ist, dass es auch modifiziert werden könnte, um das Richtige zu tun, da bin ich mir sicher), wo es ausgelöst wird, wenn Dinge wie git status(die tatsächlich jedes Mal ausgeführt werden, wenn zsh ausgeführt wird) ausgelöst werden Auf meinem Computer wird eine Eingabeaufforderung gerendert ...), die dieses aufwändige Skript, das ich habe, tatsächlich durcheinander bringt, indem eine endlose Rückkopplungsschleife erstellt wird. kqwait liefert jedoch die Informationen über die geänderte Datei und wird nicht von ausgelöst git status. Ich brauche es allerdings, um beim Schreiben zu feuern.
Steven Lu

2
$ brew install kqwait && while true; do kqwait doc/my_file.md; make; done
Joshua Cook

15

watchdog ist eine plattformübergreifende Python-API zum Überwachen von Dateien / Verzeichnissen und verfügt über ein integriertes "Tricks" -Tool, mit dem Sie Aktionen (einschließlich Shell-Befehle) auslösen können, wenn Ereignisse auftreten (einschließlich neu hinzugefügter Dateien, entfernter Dateien und geänderter Dateien).


7

Dies ist nur zu erwähnen, dass entr unter OSX eine Alternative ist, um beliebige Befehle auszuführen, wenn sich Dateien ändern. Ich finde es einfach und nützlich.



3

Bearbeiten: fsw wurde in zusammengeführt fswatch. In dieser Antwort fswsollte jetzt jeder Verweis auf lauten fswatch.

Ich habe einen fswatchErsatz in C ++ geschrieben, fswder mehrere Verbesserungen enthält:

  • Es ist ein GNU Build System-Projekt, das auf jeder unterstützten Plattform (OS X v.> = 10.6) mit aufbaut

    ./configure && make && sudo make install
    
  • Mehrere Pfade können als unterschiedliche Argumente übergeben werden:

    fsw file-0 ... file-n 
    
  • Es gibt einen detaillierten Datensatz mit allen Ereignisinformationen aus, z.

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • Die Ausgabe ist einfach zu analysieren, sodass die fswAusgabe an einen anderen Prozess weitergeleitet werden kann.

  • Die Latenz kann mit angepasst werden -l, --latency.
  • Numerische Ereignisflags können anstelle von Textflags mit geschrieben werden -n, --numeric.
  • Das Zeitformat kann mithilfe von strftimeFormatzeichenfolgen mit angepasst werden -t, --time-format.
  • Die Zeit kann die Ortszeit der Maschine (standardmäßig) oder die UTC-Zeit mit sein -u, --utc-time.

Fsw bekommen:

fswwird auf GitHub gehostet und kann beim Klonen des Repositorys abgerufen werden:

    git clone https://github.com/emcrisostomo/fsw

Fsw installieren:

fsw kann mit den folgenden Befehlen installiert werden:

    ./configure && make && sudo make install

Weitere Informationen:

Ich habe auch einen einführenden Blog-Beitrag geschrieben, in dem Sie einige Beispiele zur Funktionsweise finden fsw.


2

Mit Apple OSX- Ordneraktionen können Sie Aufgaben basierend auf Aktionen für einen Ordner automatisieren.


9
Ja, ich weiß, ich habe mehrmals versucht, das zu nutzen, habe es nie erfolgreich zum Laufen gebracht. Können Sie mir ein Beispiel geben?
Mint

1
Das ist ein Link, keine Antwort
Dan Rosenstark

2

Meine Fswatch- Gabel bietet die Funktionalität einer inotifywait -metwas weniger (keine Wartezeit, mehr! Ich habe unter Linux viel mehr Probleme mit inotifywait...) Analyse-freundlichen Ausgabe.

Es ist eine Verbesserung gegenüber dem Original, fswatchda es den tatsächlichen Pfad der geänderten Datei über STDOUT sendet, anstatt dass Sie ein Programm bereitstellen müssen, das es gabelt.

Es war absolut solide als Grundlage für eine Reihe von beängstigenden Bash-Skripten, mit denen ich Dinge automatisiere.

(dies ist nicht zum Thema gehörend) inotifywaitunter Linux erfordert andererseits eine Menge Kludges, und ich habe immer noch keinen guten Weg gefunden, um es zu verwalten, obwohl ich denke, dass etwas, das darauf basiert node.js, das Ticket sein könnte.


1
Richtig, Gabel von fswatch. Ist das bei Homebrew?
Fatuhoku

1
Die Antwort ist nein; aber sie arbeiten daran . Um es wirklich schnell zu installieren, einfach brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
Fatuhoku

1

Ich habe eine GIST dafür und die Verwendung ist ziemlich einfach

watchfiles <cmd> <paths...>

Zur Veranschaulichung wird der folgende Befehl Hello Worldjedes Mal wiedergegeben, wenn sich das file1ODER file2ändert. und die Standardintervallprüfung ist 1 Sekunde

watchfiles 'echo Hello World' /path/to/file1 /path/to/file2 

Wenn ich alle 5 Sekunden überprüfen möchte, kann ich die -tFlagge verwenden

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -vAktiviert den verboseModus, in dem Debug-Informationen angezeigt werden
  • -qmacht watchfilesleise ausführen ( #wird angezeigt, damit der Benutzer sehen kann, dass das Programm ausgeführt wird)
  • -qqmacht watchfilesganz leise ausführen
  • -h zeigt die Hilfe und Verwendung

https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55


0

Am Ende habe ich das für macOS gemacht. Ich bin sicher, das ist in vielerlei Hinsicht schrecklich:

#!/bin/sh
# watchAndRun
if [ $# -ne 2 ]; then
    echo "Use like this:"
    echo "   $0 filename-to-watch command-to-run"
    exit 1
fi
if which fswatch >/dev/null; then
    echo "Watching $1 and will run $2"
    while true; do fswatch --one-event $1 >/dev/null && $2; done
else
    echo "You might need to run: brew install fswatch"
fi

Ohne die Weile konnte ich die fswatch-Syntax nicht herausfinden. Das ist ärgerlich und macht es schwierig, das Skript zu stoppen.
Dan Rosenstark

0

Wenn Sie NodeJS verwenden möchten, können Sie ein Paket namens chokidar (oder tatsächlich chokidar-cli ) zum Ansehen verwenden und dann Folgendes verwenden rsync(im Lieferumfang des Mac enthalten):

Rsync-Befehl:

$ rsync -avz --exclude 'some-file' --exclude 'some-dir' './' '/my/destination'

Chokidar cli (global über npm installiert):

chokidar \"**/*\" -c \"your-rsync-command-above\"


-3

Hier ist eine einfache einzeilige Alternative für Benutzer, die nicht über den watchBefehl verfügen und alle 3 Sekunden einen Befehl ausführen möchten:

while :; do your-command; sleep 3; done

Es ist eine Endlosschleife, die im Grunde der folgenden entspricht:

watch -n3 your-command


3
Dies ist NICHT dasselbe wie die Verwendung einer Bibliothek, die auf Ereignisse aus dem Dateisystem wartet. Wenn in Ihrem Beispiel your-commandFestplatten-E / A ausgeführt werden, ist dies ein garantiertes Lesen / Schreiben der Festplatte alle 3 Sekunden - oder 10.800 Mal pro Stunde. Durch die Verwendung von Dateisystemereignissen wird garantiert, dass E / A (und andere teure Vorgänge) nur dann stattfinden, wenn Sie eine Datei ändern (was im Allgemeinen nur ein paar Mal pro Stunde der Fall ist).
Noah Sussman

Richtig und gut zu überlegen. Normalerweise muss ich watchvorübergehend etwas tun, um zu sehen, was etwas tut. Ich verwende meine erwähnte Technik nicht für Produktions-Apps oder ähnliches. Zum Beispiel möchte ich den Fortschritt von sehen ddund meine Technik macht es möglich ( your-commandgegebenenfalls ersetzen , um das entsprechende Signal an zu senden dd).
trusktr
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.