Esiste un comando come "guarda" o "inotifywait" sul Mac?


287

Voglio guardare una cartella sul mio Mac (Snow Leopard) e quindi eseguire uno script (dandogli il nome file di ciò che è stato appena spostato in una cartella (come parametro ... x.sh "nome file")).

Ho uno script tutto scritto in bash (x.sh) che sposterà alcuni file e altre cose sull'input $ 1 Ho solo bisogno di OSX per darmi il nome del file quando i nuovi file / cartelle vengono spostati / creati in una directory.

Qualche comando del genere?


1
Dovresti chiedere come DropBox lo fa dal momento che presumibilmente hanno provato tutte le opzioni disponibili.
Jeff Burdges,

2
@JeffBurdges Non sono così sicuro che sarebbe un'impresa facile. Tuttavia, direi dopo aver sfogliato il riferimento FSEvents di Apple sarebbe davvero sciocco se Dropbox non lo usasse. L' fswatchutilità presentata come risposta di seguito utilizza infatti questo metodo.
Steven Lu,

Risposte:


447

fswatch

fswatch è un piccolo programma che utilizza l'API FSEvents di Mac OS X per monitorare una directory. Quando viene ricevuto un evento su qualsiasi modifica a quella directory, il comando shell specificato viene eseguito da/bin/bash

Se usi GNU / Linux, inotifywatch (parte del inotify-toolspacchetto sulla maggior parte delle distribuzioni) offre funzionalità simili.

Aggiornamento: fswatch ora può essere utilizzato su molte piattaforme tra cui BSD, Debian e Windows.

Sintassi / Un semplice esempio

Il nuovo modo che può guardare più percorsi - per le versioni 1.xe successive :

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

Nota: il numero emesso da -overrà aggiunto alla fine del xargscomando se non per -I{}. Se scegli di usare quel numero, posizionalo {}ovunque nel tuo comando.

Il vecchio modo per le versioni 0.x :

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

Installazione con Homebrew

A partire dal 9/12/13 è stato aggiunto di nuovo a homebrew - yay! Quindi, aggiorna il tuo elenco di formule ( brew update) e quindi tutto ciò che devi fare è:

brew install fswatch

Installazione senza Homebrew

Digita questi comandi in Terminal.app

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

Se non si dispone di un ccompilatore sul proprio sistema, potrebbe essere necessario installare gli strumenti da riga di comando Xcode o Xcode, entrambi gratuiti. Tuttavia, se è così, probabilmente dovresti dare un'occhiata a homebrew .

Opzioni aggiuntive per la fswatchversione 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.

Le tue istruzioni o l'installazione senza homebrew non sembrano funzionare più. makegenera un errore nel non trovare un makefile. Fortunatamente, fswatch è ora su MacPorts, quindi sudo port install fswatchfunziona, per quelli di noi che usano MacPorts invece di Homebrew.
coredumperror,

Se stai usando un comando con argomenti statici (ad esempio, stavo eseguendo i miei test unitari su src e test cambiamenti) questo potrebbe non funzionare per te. Questa domanda ( stackoverflow.com/questions/25689589/… ) era il secondo pezzo di cui avevo bisogno.
jskulski,

5
Ti ascolto là fuori:fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
fionbio,

fswatch è meglio di strumenti come entr o when_changed, che presentano alcuni bug nel gestire la directory .git. fswatch è molto più professionale. Semplicemente, fswatch .monitorerai solo la directory corrente.
anonimo il

Vorrei suggerire fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]con -0per NULL. Questo funziona per me con meno compilation
boldnik,

95

È possibile utilizzare launchd a tale scopo. Launchd può essere configurato per avviare automaticamente un programma quando viene modificato un percorso di file.

Ad esempio, la seguente configurazione di avvio avvia il programma /usr/bin/loggerquando viene modificata la cartella desktop del mio account utente:

<?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>

Per attivare la configurazione, salvarla nella cartella LaunchAgents nella cartella Libreria come "logger.plist".

Dalla shell è quindi possibile utilizzare il comando launchctlper attivare logger.plist eseguendo:

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

La cartella desktop è ora monitorata. Ogni volta che viene modificato dovresti vedere un output in system.log (usa Console.app). Per disattivare logger.plist, eseguire:

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

Il file di configurazione sopra utilizza l' WatchPathsopzione. In alternativa puoi anche usare l' QueueDirectoriesopzione. Vedi la pagina man launchd per maggiori informazioni.


1
c'è un modo per farlo monitorare il cambiamento nel contenuto del file e nel percorso del file?
Cam

2
Io non la penso così. È possibile utilizzare opensnoop a tale scopo.
Sakra,

1
Ho fatto in modo che funzionasse, ma poi quando sono passato /usr/bin/loggercon il mio script Bash e "<string>path modified</strong>"ho rimosso la voce, non sono riuscito a trovare alcun modo per il mio script bash di sapere quale file sul mio desktop è stato modificato - solo che si è verificato l'evento. Ho provato a guardare $0, $1e ho ottenuto solo il nome dello script stesso, notando che gli è passato.
Volomike,

Inoltre, questa cosa si inserisce in un ciclo quando rileva un cambiamento, piuttosto che avviarsi (e arrestarsi) solo quando rileva un cambiamento? Preferirei funzionare su richiesta, non continuare a funzionare in un ciclo che mi dice che, ad esempio, 2 giorni fa, qualcosa è cambiato sul mio desktop, scrivendolo più volte nel log. Quindi, dobbiamo usare una sorta di opzione di intervallo in questo plist?
Volomike,

Grande lavoro e spiegazione
ChenSmile

37

Anche il guardiano di Facebook , disponibile tramite Homebrew, ha un bell'aspetto. Supporta anche il filtraggio:

Queste due righe stabiliscono un controllo su una directory di origine e quindi impostano un trigger denominato "buildme" che eseguirà uno strumento denominato "minify-css" ogni volta che viene modificato un file CSS. Lo strumento verrà passato un elenco dei nomi di file modificati.

$ watchman watch ~/src

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

Si noti che il percorso deve essere assoluto.


1
Questo è di gran lunga lo strumento migliore.
BentOnCoding

1
Questo è un piccolo programma molto carino: i documenti sono fantastici, non apre un ciclo infinito (che è ciò che fswatch sembra fare) e ricorda gli orologi che hai creato dopo il riavvio e li riavvia automaticamente.
Brad

21

Potresti dare un'occhiata (e forse espandere) il mio piccolo strumento kqwait. Attualmente si siede e aspetta un evento di scrittura su un singolo file, ma l' architettura di kqueue consente lo stacking di eventi gerarchici ...


Funziona finora con il leone di montagna. Molto bella!
Scott,

Quindi questo è davvero fantastico. Mi sono imbattuto in un piccolo problema con fswatch(che va bene anche, dal momento che è un involucro così leggero che potrebbe anche essere modificato per fare la cosa giusta di cui sono sicuro) in cui potrebbe sparare quando si eseguono cose come git status(che viene effettivamente eseguito ogni volta che zsh il prompt viene visualizzato sulla mia macchina ...) che in realtà un po 'rovina questo elaborato script che ho creando un loop di feedback infinito. kqwait, tuttavia, fornisce le informazioni sul file modificato e non viene attivato da git status. Ne ho bisogno per sparare sulla scrittura però.
Steven Lu,

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

15

watchdog è un'API python multipiattaforma per la visione di file / directory e ha uno strumento "trucchi" incorporato che consente di attivare azioni (inclusi i comandi di shell) quando si verificano eventi (inclusi nuovo file aggiunto, file rimosso e file modificato).


7

Questo è solo per citare entr come alternativa a OSX per eseguire comandi arbitrari quando cambiano i file. Lo trovo semplice e utile.



3

Modifica: fsw è stato unito in fswatch. In questa risposta, ogni riferimento a fswdovrebbe ora leggere fswatch.

Ho scritto un fswatchsostituto in C ++ chiamato fswche presenta diversi miglioramenti:

  • È un progetto GNU Build System che si basa su qualsiasi piattaforma supportata (OS X v.> = 10.6) con

    ./configure && make && sudo make install
    
  • Percorsi multipli possono essere passati come diversi argomenti:

    fsw file-0 ... file-n 
    
  • Scarica un record dettagliato con tutte le informazioni sull'evento come:

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • L'output è facile da analizzare in modo che l' fswoutput possa essere reindirizzato a un altro processo.

  • La latenza può essere personalizzata con -l, --latency.
  • I flag di eventi numerici possono essere scritti invece di quelli testuali con -n, --numeric.
  • Il formato dell'ora può essere personalizzato usando le strftimestringhe di formato con -t, --time-format.
  • L'ora può essere l' ora locale della macchina (per impostazione predefinita) o l'ora UTC con -u, --utc-time.

Ottenere fsw:

fswè ospitato su GitHub e può essere ottenuto clonando il suo repository:

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

Installazione di fsw:

fsw può essere installato utilizzando i seguenti comandi:

    ./configure && make && sudo make install

Ulteriori informazioni:

Ho anche scritto un post di blog introduttivo in cui puoi trovare un paio di esempi su come fswfunziona.


2

Le azioni della cartella Apple OSX ti consentono di automatizzare le attività in base alle azioni intraprese su una cartella.


9
Sì, lo so, ho provato a usarlo più volte, senza mai riuscire a farlo funzionare, potresti darmi un esempio?
Menta,

1
Questo è un link, non una risposta
Dan Rosenstark,

2

Il mio fork di fswatch offre la funzionalità di un outputinotifywait -m leggermente inotifywaitparse (no aspettare, di più! Ho molti più problemi su Linux con ...).

Si tratta di un miglioramento rispetto all'originale fswatchperché invia il percorso effettivo del file modificato su STDOUT piuttosto che richiedere all'utente di fornire un programma che prevede.

È stato solido come la base di una serie di script bash spaventosi che uso per automatizzare le cose.

(questo è fuori tema) inotifywaitsu Linux, d'altra parte, richiede molti kludges e non ho ancora trovato un buon modo per gestirlo, anche se penso che qualcosa basato su node.jspotrebbe essere il biglietto.


1
A destra, fork di fswatch. È che il Homebrew?
fatuhoku,

1
La risposta è no; ma ci stanno lavorando . Per installarlo molto velocemente, basta brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
fatuhoku,

1

Ho un GIST per questo e l'utilizzo è piuttosto semplice

watchfiles <cmd> <paths...>

Per illustrare, il seguente comando farà eco Hello Worldogni volta che file1OR file2cambia; e il controllo intervallo predefinito è 1 secondo

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

Se voglio controllare ogni 5 secondi posso usare la -tbandiera

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -vabilita la verbosemodalità che mostra le informazioni di debug
  • -qfa watchfileseseguire tranquillamente ( #verrà mostrato in modo che l'utente possa vedere il programma in esecuzione)
  • -qqfa watchfileseseguire in modo completamente silenzioso
  • -h mostra l'aiuto e l'uso

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


0

Ho finito per farlo per macOS. Sono sicuro che questo è terribile in molti modi:

#!/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

Non sono riuscito a capire la sintassi di fswatch senza il tempo. Il che è fastidioso e rende difficile la sceneggiatura.
Dan Rosenstark,

0

Se vuoi usare NodeJS, puoi usare un pacchetto chiamato chokidar (o chokidar-cli in realtà) per la visione e quindi usare rsync(incluso con Mac):

Comando Rsync:

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

Chokidar cli (installato a livello globale tramite npm):

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


-3

Ecco una semplice alternativa a riga singola per gli utenti che non dispongono del watchcomando che desiderano eseguire un comando ogni 3 secondi:

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

È un ciclo infinito che è sostanzialmente lo stesso del seguente:

watch -n3 your-command


3
Questo NON è lo stesso che usare una libreria che ascolta gli eventi dal filesystem. Se nel tuo esempio, your-commandI / O su disco, allora questo è un disco garantito in lettura / scrittura ogni 3 secondi - o 10.800 volte ogni ora. Usando gli eventi del filesystem ti verrebbe garantito che l'I / O (e altre operazioni costose) avvengono solo quando cambi un file (che generalmente è solo un paio di volte all'ora.)
Noah Sussman,

Vero e buono da considerare. Di solito ho bisogno di watchcose per un periodo di tempo temporaneo per vedere cosa sta facendo qualcosa. Non uso la mia tecnica menzionata per app di produzione o cose del genere. Ad esempio, mi piacerebbe vedere i progressi di dd, e la mia tecnica lo rende possibile (sostituendo, your-commandse del caso, per inviare il segnale appropriato a dd).
trusktr,
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.