¿Cómo ejecutar automáticamente un script cuando el contenido de un directorio cambia en Linux?

Respuestas:

17

Si tienes la suerte de estar en una distribución basada en Debian, apt-get install dnotify. Probablemente otras distribuciones tengan algo similar: busque el dnotifynombre.

dnotify es un programa simple basado en la API dnotify de Linux kernel 2.4.19 +. dnotify puede ejecutar un comando específico cada vez que cambia el contenido de un directorio específico. Se ejecuta desde la línea de comando y toma dos argumentos: uno o más directorios para monitorear y un comando para ejecutar cada vez que un directorio ha cambiado. Las opciones controlan en qué eventos desencadenar: cuando un archivo se leyó en el directorio, cuándo se creó, se eliminó, etc.

Si desea manejar esto dentro de su propio programa, dnotify es también la API que desea usar.

MikeyB
fuente
44
@MikeB, después de buscar en Google dnotify que sugeriste, terminé usando inotify, que aparentemente lo reemplaza. Gracias por señalarme la dirección correcta. apt-get install inotify-tools
GeneQ
77
@GeneQ, inotify ha reemplazado a dnotify.
David
1
Del mismo modo en Gentoo:emerge inotify-tools
James Sneeringer
Sí, iba a decir que el kernel 2.4.19 es algo antiguo ;-) inotify es el camino a seguir.
David Z
Oh sí ... olvidé cuál era más reciente :)
MikeyB
12

Puede ejecutar un script con las herramientas de inotify, algo como esto. Observará el directorio en busca de cambios en archivos modificados, archivos nuevos y archivos eliminados, luego ejecutará el script.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
usuario7119
fuente
Solo tenga en cuenta que si el directorio de origen cambia mientras se está copiando, inotifywait NO lo verá y esos cambios no se copiarán hasta que se realicen más cambios una vez que la copia haya finalizado. Sin embargo, probablemente no sea un problema.
Raúl Salinas-Monteagudo
¿Cómo puedes ejecutar esto en modo demonio?
Chris F
4

incron es básicamente lo que quieres, creo. Utiliza inotify como mecanismo de notificación (que, como otros han señalado, reemplaza a dnotify), pero no requiere un script que se ejecute continuamente, usando inotifywait o similar (aunque, obviamente, el demonio incron se ejecuta todo el tiempo). Los 'crontabs' de todo el sistema y los 'crontabs' de usuario son compatibles de manera similar al cron estándar, pero en lugar de especificar los tiempos como desencadenantes, se utilizan eventos de notificación y nombres de archivos / directorios.

incron está empaquetado para muchas distribuciones, incluidas Ubuntu y Debian, creo.

Andrew Ferrier
fuente
0

Hay una pieza de software únicamente para este propósito, autoenv Es posible que desee verificarlo.

DukeLion
fuente
0

entr es la herramienta de notificación de archivos más simple y composable que he visto. Su uso está optimizado para mirar archivos en lugar de directorios, pero también puede resolver su caso.

Para detectar y actuar sobre el archivo agregado, combínelo con otras herramientas como por ejemplo make. entrno envía el nombre ni nada de eso, simplemente ejecuta lo que le dijiste que ejecutara.

Para buscar archivos agregados en un directorio:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Si también desea actuar cuando cambia un archivo existente:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... y ahí es donde el mecanismo de bucle es útil, ya que la findexpresión se ejecutará nuevamente si se agrega un archivo.

Si desea un mejor manejo de errores y quiere asegurarse de que las cosas solo se ejecuten una vez por archivo agregado / eliminado, las cosas se ponen un poco extrañas, pero para estos casos simples es genial.


EDITAR: si desea hacer esto a nivel de sistema, algo como incron , simplemente agregue el script a su administrador de procesos favorito (como s6 , runit , systemd o sysvinit y omita el ciclo:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

La execy la sustitución del proceso ( <(...)) son importantes cuando se ejecuta desde un administrador de procesos, para manejar la señalización correctamente (es decir, para sacar el shell del camino).

clacke
fuente