Existe-t-il une commande comme «watch» ou «inotifywait» sur le Mac?

287

Je veux regarder un dossier sur mon Mac (Snow Leopard) puis exécuter un script (en lui donnant le nom de fichier de ce qui vient d'être déplacé dans un dossier (comme paramètre ... x.sh "nom de fichier")).

J'ai un script tout écrit en bash (x.sh) qui déplacera certains fichiers et autres choses en entrée $ 1 J'ai juste besoin d'OSX pour me donner le nom du fichier lorsque de nouveaux fichiers / dossiers sont déplacés / créés dans un répertoire.

Une telle commande?

menthe
la source
1
Vous devriez vous demander comment DropBox le fait, car ils ont probablement essayé toutes les options disponibles.
Jeff Burdges
2
@JeffBurdges Je ne suis pas sûr que ce serait une entreprise facile. Cependant, je dirais qu'après avoir survolé la référence FSEvents d'Apple, ce serait vraiment stupide si Dropbox n'en faisait pas usage. L' fswatchutilité présentée comme réponse ci-dessous utilise en fait cette méthode.
Steven Lu

Réponses:

447

fswatch

fswatch est un petit programme utilisant l'API FSEvents de Mac OS X pour surveiller un répertoire. Lorsqu'un événement concernant une modification de ce répertoire est reçu, la commande shell spécifiée est exécutée par/bin/bash

Si vous êtes sous GNU / Linux, inotifywatch (qui fait partie du inotify-toolspackage sur la plupart des distributions) fournit des fonctionnalités similaires.

Mise à jour: fswatch peut désormais être utilisée sur de nombreuses plates-formes, notamment BSD, Debian et Windows.

Syntaxe / Un exemple simple

La nouvelle façon de regarder plusieurs chemins - pour les versions 1.x et supérieures :

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

Remarque: Le nombre sorti par -osera ajouté à la fin de la xargscommande si ce n'est pour le -I{}. Si vous choisissez d'utiliser ce numéro, placez-le {}n'importe où dans votre commande.

L'ancienne méthode pour les versions 0.x :

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

Installation avec Homebrew

Le 9/12/13, il a été ajouté à homebrew - yay! Donc, mettez à jour votre liste de formules ( brew update) et tout ce que vous avez à faire est de:

brew install fswatch

Installation sans Homebrew

Tapez ces commandes dans Terminal.app

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

Si vous n'avez pas de ccompilateur sur votre système, vous devrez peut-être installer les outils de ligne de commande Xcode ou Xcode - tous deux gratuits. Cependant, si tel est le cas, vous devriez probablement vérifier les homebrews .

Options supplémentaires pour la 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.
cwd
la source
Vos instructions ou l'installation sans homebrew ne semblent plus fonctionner. makerenvoie une erreur de ne pas trouver un makefile. Heureusement, fswatch est maintenant sur MacPorts, donc ça sudo port install fswatchmarche, pour ceux d'entre nous qui utilisent MacPorts au lieu de Homebrew.
coredumperror
Si vous utilisez une commande avec des arguments statiques (par exemple, j'exécutais mes tests unitaires sur src et teste les modifications), cela pourrait ne pas fonctionner pour vous. Cette question ( stackoverflow.com/questions/25689589/… ) était la deuxième pièce dont j'avais besoin.
jskulski
5
Je vous entends là-bas:fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
fionbio
fswatch est meilleur que des outils comme entr ou when_changed, qui ont quelques bugs lors du traitement du répertoire .git. fswatch est beaucoup plus professionnel. Simplement, vous fswatch .surveillerez simplement le répertoire actuel.
anonyme
Je suggérerais fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]avec -0pour NULLs. Celui-ci fonctionne pour moi pour moins de compilation
boldnik
95

Vous pouvez utiliser launchd à cet effet. Launchd peut être configuré pour lancer automatiquement un programme lorsqu'un chemin de fichier est modifié.

Par exemple, le plist de configuration de launchd suivant lancera le programme /usr/bin/loggerlorsque le dossier du bureau de mon compte d'utilisateur est modifié:

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

Pour activer le plist de configuration, enregistrez-le dans le dossier LaunchAgents de votre dossier Library sous le nom "logger.plist".

Depuis le shell, vous pouvez ensuite utiliser la commande launchctlpour activer le logger.plist en exécutant:

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

Le dossier du bureau est maintenant surveillé. Chaque fois qu'il est modifié, vous devriez voir une sortie dans le system.log (utilisez Console.app). Pour désactiver le logger.plist, exécutez:

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

Le fichier de configuration ci-dessus utilise l' WatchPathsoption. Alternativement, vous pouvez également utiliser l' QueueDirectoriesoption. Consultez la page de manuel launchd pour plus d'informations.

sakra
la source
1
Existe-t-il un moyen de surveiller les modifications du contenu du fichier ainsi que le chemin d'accès au fichier?
Cam
2
Je ne pense pas. Vous pouvez utiliser opensnoop à cet effet.
sakra
1
J'ai réussi à le faire fonctionner, mais quand j'ai changé /usr/bin/loggerde script Bash et supprimé l' "<string>path modified</strong>"entrée, je n'ai trouvé aucun moyen pour mon script bash de savoir quel fichier sur mon bureau a été modifié - juste que l'événement s'est produit. J'ai essayé de regarder $0, $1et je n'ai obtenu que le nom du script lui-même, en notant qu'il lui avait été transmis.
Volomike
En outre, cette chose entre-t-elle en boucle une fois qu'elle détecte un changement, plutôt que de se lancer (et d'arrêter) uniquement lorsqu'elle détecte un changement? Je préfère que cela fonctionne à la demande, pas continuer à tourner en boucle en me disant que, par exemple, il y a 2 jours, quelque chose a changé sur mon bureau, en l'écrivant dans le journal encore et encore. Alors, devons-nous utiliser une sorte d'option d'intervalle dans cette liste?
Volomike
Grand travail et explication
ChenSmile
37

Le gardien de Facebook , disponible via Homebrew, a également l'air sympa. Il prend également en charge le filtrage:

Ces deux lignes établissent une surveillance sur un répertoire source, puis définissent un déclencheur nommé "buildme" qui exécutera un outil nommé "minify-css" chaque fois qu'un fichier CSS est modifié. L'outil recevra une liste des noms de fichiers modifiés.

$ watchman watch ~/src

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

Notez que le chemin doit être absolu.

Jakub Holý
la source
1
C'est de loin le meilleur outil.
BentOnCoding
1
C'est un très joli petit programme: les documents sont excellents, il n'ouvre pas une boucle infinie (ce que semble faire fswatch) et il se souvient des montres que vous avez créées après le redémarrage et les redémarre automatiquement.
Brad
21

Vous voudrez peut-être jeter un œil à (et peut-être étendre) mon petit outil kqwait. Actuellement, il reste assis et attend un événement d'écriture sur un seul fichier, mais l' architecture kqueue permet un empilement d'événements hiérarchique ...

sschober
la source
Fonctionne jusqu'à présent sur le lion de montagne. Très agréable!
Scott
Donc c'est vraiment génial. Je suis tombé sur un petit problème avec fswatch(ce qui est bien aussi, car c'est un emballage si léger qu'il pourrait également être modifié pour faire la bonne chose, je suis sûr) où il se déclencherait lors de l'exécution de choses comme git status(qui est en fait exécuté à chaque fois que zsh l'invite est rendue sur ma machine ...) qui en fait un peu foiré ce script élaboré que j'ai en créant une boucle de rétroaction sans fin. kqwait, cependant, fournit les informations sur le fichier modifié et n'est pas déclenché par git status. Mais j'en ai besoin pour tirer en écriture.
Steven Lu
2
$ brew install kqwait && while true; do kqwait doc/my_file.md; make; done
Joshua Cook
15

watchdog est une API python multiplateforme pour regarder les fichiers / répertoires, et il dispose d'un outil "astuces" intégré qui vous permet de déclencher des actions (y compris les commandes shell) lorsque des événements se produisent (y compris un nouveau fichier ajouté, un fichier supprimé et un fichier modifié).

gfxmonk
la source
7

C'est juste pour mentionner entr comme alternative sur OSX pour exécuter des commandes arbitraires lorsque les fichiers changent. Je le trouve simple et utile.

Donny Winston
la source
5

Voici un one-liner utilisant sschoberl' outil de .

$ while true; do kqwait ./file-to-watch.js; script-to-execute.sh; done
Joshua Cook
la source
$ brew install kqwait
Joshua Cook
3

Modifier: fsw a été fusionné fswatch. Dans cette réponse, toute référence à fswdevrait maintenant être lue fswatch.

J'ai écrit un fswatchremplacement en C ++ appelé fswqui présente plusieurs améliorations:

  • C'est un projet GNU Build System qui s'appuie sur n'importe quelle plate-forme prise en charge (OS X v.> = 10.6) avec

    ./configure && make && sudo make install
    
  • Plusieurs chemins peuvent être passés sous différents arguments:

    fsw file-0 ... file-n 
    
  • Il sauvegarde un enregistrement détaillé avec toutes les informations sur l'événement, telles que:

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • Sa sortie est facile à analyser afin que la fswsortie puisse être dirigée vers un autre processus.

  • La latence peut être personnalisée avec -l, --latency.
  • Des drapeaux d'événements numériques peuvent être écrits au lieu de textuels avec -n, --numeric.
  • Le format d'heure peut être personnalisé à l'aide de strftimechaînes de format avec -t, --time-format.
  • L'heure peut être l' heure locale de la machine (par défaut) ou l'heure UTC avec -u, --utc-time.

Obtenir fsw:

fswest hébergé sur GitHub et peut être obtenu en clonant son référentiel:

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

Installation de fsw:

fsw peut être installé à l'aide des commandes suivantes:

    ./configure && make && sudo make install

Plus d'informations:

J'ai également écrit un billet de blog d' introduction où vous pouvez trouver quelques exemples sur le fswfonctionnement.

Enrico M. Crisostomo
la source
2

Les actions du dossier Apple OSX vous permettent d'automatiser les tâches en fonction des actions prises sur un dossier.

Asaph
la source
9
Ouais je sais, j'ai essayé de l'utiliser plusieurs fois, je n'ai jamais réussi à le faire fonctionner, pourriez-vous me donner un exemple?
Mint
1
C'est un lien, pas une réponse
Dan Rosenstark
2

Ma fourchette de fswatch fournit la fonctionnalité inotifywait -mavec un peu moins (pas d'attente, plus! J'ai beaucoup plus de problèmes sur Linux avec inotifywait...) une sortie conviviale pour l'analyse.

C'est une amélioration par rapport à l'original fswatchcar il envoie le chemin réel du fichier modifié sur STDOUT plutôt que de vous obliger à fournir un programme qu'il bifurque.

Cela a été solide comme fondement d'une série de scripts bash effrayants que j'utilise pour automatiser des trucs.

(ceci est hors sujet) inotifywaitsous Linux, d'autre part, nécessite beaucoup de compliments et je n'ai toujours pas trouvé un bon moyen de le gérer, bien que je pense que quelque chose basé sur node.jspourrait être le ticket.

Steven Lu
la source
1
À droite, fourchette de fswatch. Est- ce sur Homebrew?
fatuhoku
1
La réponse est non; mais ils y travaillent . Pour l'installer très rapidement juste brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
fatuhoku
1

J'ai un GIST pour cela et l'utilisation est assez simple

watchfiles <cmd> <paths...>

Pour illustrer, la commande suivante fera écho à Hello Worldchaque fois que file1OU file2changera; et la vérification de l'intervalle par défaut est de 1 seconde

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

Si je veux vérifier toutes les 5 secondes, je peux utiliser le -tdrapeau

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -vactive le verbosemode qui affiche les informations de débogage
  • -qfait watchfilesexécuter tranquillement ( #sera affiché pour que l'utilisateur puisse voir que le programme s'exécute)
  • -qqfait watchfilesexécuter complètement silencieusement
  • -h montre l'aide et l'utilisation

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

thiagoh
la source
0

J'ai fini par le faire pour macOS. Je suis sûr que c'est terrible à bien des égards:

#!/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
Dan Rosenstark
la source
Je ne pouvais pas comprendre la syntaxe fswatch sans le temps. Ce qui est ennuyeux et rend le script difficile à arrêter.
Dan Rosenstark
0

Si vous souhaitez utiliser NodeJS, vous pouvez utiliser un package appelé chokidar (ou chokidar-cli en fait) pour l'observation, puis utiliserrsync (inclus avec Mac):

Commande Rsync:

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

Chokidar cli (installé globalement via npm):

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

prograhammer
la source
-3

Voici une alternative simple sur une seule ligne pour les utilisateurs qui n'ont pas la watchcommande et qui souhaitent exécuter une commande toutes les 3 secondes:

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

C'est une boucle infinie qui est fondamentalement la même que celle qui suit:

watch -n3 your-command

trusktr
la source
3
Ce n'est PAS la même chose que d'utiliser une bibliothèque qui écoute les événements du système de fichiers. Si dans votre exemple, les your-commandE / S de disque sont effectuées, il s'agit d'une lecture / écriture de disque garantie toutes les 3 secondes - ou 10 800 fois par heure. En utilisant des événements de système de fichiers, vous auriez la garantie que les E / S (et autres opérations coûteuses) ne se produisent que lorsque vous modifiez un fichier (ce qui n'est généralement que quelques fois par heure).
Noah Sussman
Vrai et bon à considérer. J'ai généralement besoin de watchchoses pendant des périodes temporaires pour voir ce que quelque chose fait. Je n'utilise pas ma technique mentionnée pour les applications de production ou quelque chose comme ça. Par exemple, j'aimerais voir la progression de dd, et ma technique y arrive (en remplaçant your-commandle cas échéant pour envoyer le signal approprié dd).
trusktr