desarrollo-web-br-bd.com

¿Script para monitorear la carpeta de nuevos archivos?

¿Cómo detectar nuevos archivos en una carpeta con un script bash ? Me gustaría procesar los archivos tan pronto como se creen en la carpeta. ¿Es posible hacerlo o tengo que programar un script con cron que busca nuevos archivos cada minuto más o menos?

141
ihatetoregister

Debería considerar usar inotifywait, como ejemplo:

inotifywait -m /path -e create -e moved_to |
    while read dir action file; do
        echo "The file '$file' appeared in directory '$dir' via '$action'"
        # do something with the file
    done

En Ubuntu inotifywait es proporcionado por el inotify-tools paquete. A partir de la versión 3.13 (actual en Ubuntu 12.04) inotifywait incluirá el nombre de archivo sin la opción -f. Las versiones anteriores pueden necesitar ser coaccionadas. Es importante tener en cuenta que el -e opción a inotifywait es la mejor manera de hacer el filtrado de eventos. Además, su comando read puede asignar la salida posicional en múltiples variables que puede elegir usar o ignorar. No es necesario usar grep/sed/awk para preprocesar la salida.

168
enzotib

Acabo de preparar esto y no veo grandes problemas con él, aparte de una pequeña posibilidad de que falten archivos entre las comprobaciones.

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

Si el procesamiento de su archivo no toma demasiado tiempo, no debe perderse ningún archivo nuevo. También podría poner en segundo plano las actividades ... No es a prueba de balas, pero sirve para algunos propósitos sin herramientas externas como inotify.

28
Michael Sacchi

Prefiero incron , ya que es más fácil de administrar. Esencialmente es un servicio que aprovecha inotify y puede configurar configuraciones para tomar medidas basadas en las operaciones de cambio de archivos.

Ex:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh

Puede ver un ejemplo completo aquí: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

27
rynop

Puedes usar watch en tu script

watch -n 0.1 ls <your_folder>

Monitorea su carpeta y le enumera todo lo que contiene cada 0.1 segundos

inconveniente

No es en tiempo real, por lo que si un archivo fue creado y eliminado en menos de 0.1 segundo, entonces esto no funcionaría, watch solo admite un mínimo de 0.1 segundos.

26
GypsyCosmonaut

Supongo que la carpeta de destino (la llamaré isempty solo por conveniencia) está vacía y está esperando que se suelten uno o más archivos allí.

Puede usar el siguiente comando:

ls -1A isempty | wc -l

solo para verificar si la carpeta todavía está vacía, de hecho devolverá un 0 si no hay un archivo nuevo (de ahí que la carpeta isempty todavía esté vacía) o, por otro lado, devolverá un valor mayor que 0 (en realidad, el número de archivos actualmente en la carpeta).

Dicho esto, una prueba tonta si/entonces puede hacer el resto del trabajo:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

Por supuesto, la función do_something Tendrá que manipular los archivos dentro de la carpeta isempty y luego eliminarlos de la carpeta después del procesamiento.

Agregar una línea como la siguiente en su crontab ejecutará la comprobación una vez por minuto y activará la acción do_something Si la carpeta no está vacía, por supuesto:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
9
ztank1013

entr

Usar entr es la nueva forma de hacerlo (es multiplataforma). Nota entr no utiliza sondeo, lo que le da una gran ventaja sobre muchas de las alternativas.

Utiliza kqueue(2) o inotify(7) para evitar el sondeo. entr fue escrito para hacer que la retroalimentación rápida y las pruebas automatizadas sean naturales y completamente normales.

En BSD usa pledge(2)

Puedes instalarlo con

apt-get install entr
dnf install entr
brew install entr

Puede rastrear un directorio para nuevas incorporaciones usando

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

Opciones explicadas (de los documentos),

  • -d Rastree los directorios de archivos regulares proporcionados como entrada y salga si se agrega un nuevo archivo. Esta opción también permite que los directorios se especifiquen explícitamente. Los archivos con nombres que comienzan con "." Se ignoran.
  • -n Ejecutar en modo no interactivo. En este modo, entr no intenta leer desde el TTY ni cambiar sus propiedades.
  • -r Vuelva a cargar un proceso secundario persistente. Al igual que con el modo de operación estándar, una utilidad que finaliza no se ejecuta nuevamente hasta que se procesa un sistema de archivos o un evento de teclado. SIGTERM se usa para terminar la utilidad antes de que se reinicie. Se crea un grupo de procesos para evitar que los scripts de Shell enmascaren señales. entr espera a que salga la utilidad para garantizar que se hayan cerrado recursos como los sockets. El control del TTY no se transfiere al proceso hijo.
8
Evan Carroll

Si desea detectar nuevos archivos, luego procesarlos y, al final, eliminar los archivos procesados ​​que puede usar systemd.path . Este método se basa en inotify. Hay una opción DirectoryNotEmpty, por lo que systemd puede ejecutar su script siempre que detecta cualquier archivo en el directorio. Debe recordar que funcionará solo si puede eliminar los archivos procesados ​​y el script deja el directorio vacío.

Primero prepare el archivo mymonitor.service

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

luego vaya a mymonitor.path para definir la ruta

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Si el nombre del archivo .path es el mismo que el del servicio, no es necesario especificar el nombre del servicio en el archivo .path.

Se basa en Monitoreo del acceso a archivos para Dummies

7
Dawid Wolski

Bash no puede hacer esto fácilmente. Básicamente, tendría que obtener una lista de todos los archivos en la carpeta y obtener periódicamente una nueva lista y compararlos para ver qué ha cambiado.

Lo que estás buscando se llama inotify. Está integrado en el kernel de Linux y básicamente puedes sentarte allí esperando que algo suceda en ese momento, inotify regresa y dice 'hey, hay un nuevo archivo llamado foobar'

Para lograr lo que quieres, deberías cambiar a algo como Perl y usar Linux :: Inotify2 (python probablemente también sea compatible con inotify, pero soy una persona de Perl).

2
Patrick

Esto funciona en Cygwin y Linux. Algunas de las soluciones anteriores que escriben un archivo harán que el disco se dañe. Este scipt no tiene ese problema:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG=`ls -1 | md5sum | cut -c1-32`
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done
0
user1186515

A continuación se muestra una versión abreviada de ejemplo en stackoverflow que he probado e incorporado a uno de mis proyectos que requiere la supervisión de directorios específicos.

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            Elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

Aquí hay un enlace a un script que usa una versión modificada de arriba para descifrar automáticamente los archivos o directorios encontrados en su punto de montaje sshfs; El proyecto mencionado anteriormente.

0
S0AndS0