¿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?
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.
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.
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/
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.
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
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)
oinotify(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.
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
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).
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
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.