¿Hay un comando como "ver" o "inotifywait" en la Mac?

287

Quiero ver una carpeta en mi Mac (Snow Leopard) y luego ejecutar un script (dándole el nombre de archivo de lo que se acaba de mover a una carpeta (como parámetro ... x.sh "nombre de archivo")).

Tengo un script escrito en bash (x.sh) que moverá algunos archivos y otras cosas en la entrada $ 1. Solo necesito que OSX me dé el nombre del archivo cuando se mueven / crean nuevos archivos / carpetas en un directorio.

Cualquiera de esos comandos?

menta
fuente
1
Debe preguntar cómo lo hace DropBox, ya que presumiblemente probaron todas las opciones disponibles.
Jeff Burdges
2
@JeffBurdges No estoy tan seguro de que sea una tarea fácil. Sin embargo, diría que después de hojear la referencia FSEvents de Apple, sería realmente una tontería si Dropbox no estuviera haciendo uso de esto. La fswatchutilidad presentada como una respuesta a continuación de hecho utiliza este método.
Steven Lu

Respuestas:

447

fswatch

fswatch es un pequeño programa que utiliza la API FSEvents de Mac OS X para monitorear un directorio. Cuando se recibe un evento sobre cualquier cambio en ese directorio, el comando de shell especificado es ejecutado por/bin/bash

Si está en GNU / Linux, inotifywatch (parte del inotify-toolspaquete en la mayoría de las distribuciones) proporciona una funcionalidad similar.

Actualización: fswatch ahora se puede usar en muchas plataformas, incluidas BSD, Debian y Windows.

Sintaxis / Un ejemplo simple

La nueva forma de ver múltiples rutas: para las versiones 1.xy superiores :

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

Nota: El número de salida por -ose agregará al final del xargscomando si no fuera por el -I{}. Si elige usar ese número, colóquelo {}en cualquier lugar de su comando.

La forma más antigua para las versiones 0.x :

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

Instalación con Homebrew

A partir del 12/09/13 se volvió a agregar a homebrew , ¡sí! Entonces, actualice su lista de fórmulas ( brew update) y luego todo lo que necesita hacer es:

brew install fswatch

Instalación sin Homebrew

Escriba estos comandos en Terminal.app

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

Si no tiene un ccompilador en su sistema, es posible que necesite instalar las herramientas de línea de comandos Xcode o Xcode, ambas gratuitas. Sin embargo, si ese es el caso, probablemente deberías echarle un vistazo a homebrew .

Opciones adicionales para la fswatchversión 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
fuente
Sus instrucciones o instalación sin homebrew ya no parecen funcionar. makearroja un error sobre no encontrar un archivo MAKE. Afortunadamente, fswatch ahora está en MacPorts, por lo que sudo port install fswatchfunciona, para aquellos de nosotros que usamos MacPorts en lugar de Homebrew.
coredumperror
Si está utilizando un comando con argumentos estáticos (por ejemplo, estaba ejecutando mis pruebas unitarias en src y cambios de prueba), esto podría no funcionar para usted. Esta pregunta ( stackoverflow.com/questions/25689589/… ) fue la segunda pieza que necesitaba.
jskulski
55
Te escucho por ahí:fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
fionbio
fswatch es mejor que herramientas como entr o when_changed, que tienen algunos errores al tratar con el directorio .git. fswatch es mucho más profesional. Simplemente, solo fswatch .monitoreará el directorio actual.
anónimo
Sugeriría fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]con -0para NULLs. Este funciona para mí por menos compilación
boldnik
95

Puede usar launchd para ese propósito. Launchd puede configurarse para iniciar automáticamente un programa cuando se modifica una ruta de archivo.

Por ejemplo, la siguiente lista de configuración de launchd iniciará el programa /usr/bin/loggercuando se modifique la carpeta de escritorio de mi cuenta de usuario:

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

Para activar el config plist guárdelo en la carpeta LaunchAgents en su carpeta Library como "logger.plist".

Desde el shell, puede usar el comando launchctlpara activar logger.plist ejecutando:

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

La carpeta del escritorio ahora está siendo monitoreada. Cada vez que se cambia, debería ver una salida en system.log (use Console.app). Para desactivar logger.plist, ejecute:

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

El archivo de configuración anterior usa la WatchPathsopción. Alternativamente, también puede usar la QueueDirectoriesopción. Consulte la página de manual de launchd para obtener más información.

sakra
fuente
1
¿Hay alguna manera de que supervise el cambio en el contenido del archivo, así como la ruta del archivo?
Cam
2
No lo creo. Puede usar opensnoop para ese propósito.
sakra
1
Lo hice funcionar, pero cuando cambié /usr/bin/loggercon mi script Bash y eliminé la "<string>path modified</strong>"entrada, no pude encontrar ninguna manera para que mi script bash supiera qué archivo en mi escritorio se modificó, solo que ocurrió el evento. Traté de mirar $0, $1y solo obtuve el nombre del script en sí, notando que se lo pasé.
Volomike
Además, ¿esta cosa entra en un bucle una vez que detecta un cambio, en lugar de solo iniciarse (y detenerse) cuando detecta un cambio? Prefiero que funcione bajo demanda, no seguir corriendo en un bucle diciéndome que, por ejemplo, hace 2 días, algo cambió en mi escritorio, escribiendo eso en el registro una y otra vez. Entonces, ¿necesitamos usar algún tipo de opción de intervalo en esta lista?
Volomike
Gran trabajo y
explicación
37

El vigilante de Facebook , disponible a través de Homebrew, también se ve bien. También es compatible con el filtrado:

Estas dos líneas establecen un reloj en un directorio fuente y luego configuran un disparador llamado "buildme" que ejecutará una herramienta llamada "minify-css" cada vez que se cambie un archivo CSS. La herramienta recibirá una lista de los nombres de archivo modificados.

$ watchman watch ~/src

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

Tenga en cuenta que la ruta debe ser absoluta.

Jakub Holý
fuente
1
Esta es, de lejos, la mejor herramienta.
BentOnCoding
1
Este es un pequeño programa muy agradable: los documentos son geniales, no abre un bucle infinito (que es lo que parece hacer fswatch) y recuerda los relojes que ha creado después del reinicio y los reinicia automáticamente.
Brad
21

Es posible que desee echar un vistazo (y tal vez expandir) mi pequeña herramienta kqwait. Actualmente solo se sienta y espera un evento de escritura en un solo archivo, pero la arquitectura kqueue permite el apilamiento jerárquico de eventos ...

sschober
fuente
Funciona hasta ahora en el león de montaña. ¡Muy agradable!
Scott
Así que esto es realmente asombroso. Me encontré con un pequeño problema con fswatch(que también está bien, ya que es un envoltorio tan ligero que también podría modificarse para hacer lo correcto, estoy seguro) donde se dispararía al ejecutar cosas como git status(que en realidad se ejecuta cada vez que zsh el indicador se procesa en mi máquina ...) que realmente arruina este elaborado script que tengo al crear un bucle de retroalimentación interminable. kqwait, sin embargo, proporciona la información sobre el archivo modificado y no se activa git status. Sin embargo, lo necesito para disparar en escritura.
Steven Lu
2
$ brew install kqwait && while true; do kqwait doc/my_file.md; make; done
Joshua Cook
15

watchdog es una API de Python multiplataforma para ver archivos / directorios, y tiene una herramienta integrada de "trucos" que le permite activar acciones (incluidos los comandos de shell) cuando se producen eventos (incluido el nuevo archivo agregado, el archivo eliminado y el archivo modificado).

gfxmonk
fuente
7

Esto es solo para mencionar entr como una alternativa en OSX para ejecutar comandos arbitrarios cuando cambian los archivos. Lo encuentro simple y útil.

Donny Winston
fuente
5

Aquí hay una línea usando sschoberla herramienta de .

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

Editar: fsw se ha fusionado con fswatch. En esta respuesta, cualquier referencia a fswdebería leer ahora fswatch.

Escribí un fswatchreemplazo en C ++ llamado fswque presenta varias mejoras:

  • Es un proyecto de GNU Build System que se basa en cualquier plataforma compatible (OS X v.> = 10.6) con

    ./configure && make && sudo make install
    
  • Se pueden pasar múltiples rutas como argumentos diferentes:

    fsw file-0 ... file-n 
    
  • Vuelca un registro detallado con toda la información del evento, como:

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • Su salida es fácil de analizar para que la fswsalida se pueda canalizar a otro proceso.

  • La latencia se puede personalizar con -l, --latency.
  • Se pueden escribir banderas de eventos numéricos en lugar de textuales con -n, --numeric .
  • El formato de hora se puede personalizar utilizando strftimecadenas de formato con -t, --time-format.
  • La hora puede ser la hora local de la máquina (por defecto) o la hora UTC con -u, --utc-time.

Obteniendo fsw:

fswestá alojado en GitHub y se puede obtener clonando su repositorio:

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

Instalación de fsw:

fsw se puede instalar con los siguientes comandos:

    ./configure && make && sudo make install

Más información:

También escribí una publicación introductoria en el blog donde puedes encontrar un par de ejemplos sobre cómo fswfunciona.

Enrico M. Crisostomo
fuente
2

Las acciones de carpeta OSX de Apple le permiten automatizar tareas basadas en acciones tomadas en una carpeta.

Asaph
fuente
9
Sí, lo sé, he intentado usar eso varias veces, nunca lo he conseguido, ¿podrías darme un ejemplo?
Menta el
1
Ese es un enlace, no una respuesta
Dan Rosenstark
2

Mi bifurcación de fswatch proporciona la funcionalidad de un inotifywait -mpoco menos (sin esperar, ¡más! Tengo muchos más problemas en Linux con inotifywait...) salida fácil de analizar.

Es una mejora con respecto al original fswatchporque envía la ruta real del archivo modificado a través de STDOUT en lugar de requerirle que proporcione un programa que bifurca.

Ha sido sólida como la base de una serie de scripts de bash que uso para automatizar cosas.

(esto está fuera de tema) inotifywaiten Linux, por otro lado, requiere muchos errores y aún no he descubierto una buena forma de administrarlo, aunque creo que algo basado en node.jspodría ser el ticket.

Steven Lu
fuente
1
Derecha, tenedor de fswatch. Es que el Homebrew?
fatuhoku
1
La respuesta es no; pero están trabajando en eso . Para instalarlo realmente rápido solo brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
fatuhoku
1

Tengo un GIST para esto y el uso es bastante simple

watchfiles <cmd> <paths...>

Para ilustrar, el siguiente comando hará eco Hello Worldcada vez que file1O file2cambie; y la comprobación de intervalo predeterminada es 1 segundo

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

Si quiero verificar cada 5 segundos, puedo usar la -tbandera

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -vhabilita el verbosemodo que muestra información de depuración
  • -qhace que se watchfilesejecute en silencio ( #se mostrará para que el usuario pueda ver que el programa se está ejecutando)
  • -qqhace watchfilesejecutar completamente en silencio
  • -h muestra la ayuda y el uso

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

thiagoh
fuente
0

Terminé haciendo esto para macOS. Estoy seguro de que esto es terrible en muchos sentidos:

#!/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
fuente
No podría entender la sintaxis de fswatch sin el tiempo. Lo cual es molesto y hace que el guión sea difícil de detener.
Dan Rosenstark
0

Si desea usar NodeJS, puede usar un paquete llamado chokidar (o chokidar-cli en realidad) para la observación y luego usarrsync (incluido con Mac):

Comando Rsync:

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

Chokidar cli (instalado globalmente a través de npm):

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

martillo programador
fuente
-3

Aquí hay una alternativa simple de una sola línea para usuarios que no tienen el watchcomando que desean ejecutar un comando cada 3 segundos:

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

Es un bucle infinito que es básicamente lo mismo que hacer lo siguiente:

watch -n3 your-command

trusktr
fuente
3
Esto NO es lo mismo que usar una biblioteca que escucha eventos del sistema de archivos. Si en su ejemplo, your-commandhace E / S de disco, entonces esa es una lectura / escritura de disco garantizada cada 3 segundos, o 10.800 veces cada hora. Mediante el uso de eventos del sistema de archivos que le puede garantizar que E / S (y otras operaciones costosas) sólo ocurren cuando se cambia un archivo (que por lo general es sólo un par de veces por hora.)
Noé Sussman
Es cierto, y es bueno considerarlo. Por lo general, necesito watchcosas por períodos temporales para ver qué está haciendo algo. No uso mi técnica mencionada para aplicaciones de producción ni nada de eso. Por ejemplo, me gustaría ver el progreso de dd, y mi técnica lo hace posible (reemplazando your-commandsegún corresponda para enviar la señal adecuada dd).
trusktr