inotifywait是linux下最轻量实时监听目录变化的工具,基于内核事件通知,需安装inotify-tools,使用时应加-m、-r、-e create或moved_to,并配合while read循环及--format '%w%f'确保可靠捕获文件变动。

用 inotifywait 实时监听目录变化最轻量
Linux 下监听目录文件变动,inotifywait 是最直接、开销最小的选择,不用轮询,内核级事件通知,适合生产环境长期运行。它属于 inotify-tools 包,多数发行版需手动安装:sudo apt install inotify-tools(Debian/Ubuntu)或 sudo yum install inotify-tools(CentOS/RHEL)。
常见错误是直接写死路径却不处理空格或特殊字符,或忽略子目录递归监听需求:
-
inotifywait -m /path默认只监听一级目录,新文件放入子目录不会触发 —— 加-r才递归 - 没加
-e create会导致重命名、移动进来的文件被漏掉(create捕获新建和移动入事件) - 脚本里用
$1直接接文件名,但inotifywait -m输出含多列(事件类型、文件名),需用--format '%w%f'或解析输出
基础循环监听结构必须带 -m 和 while read
inotifywait -m 是持续监听模式,但它本身只输出一次就退出;要实现“一直等新文件”,必须套一层 while read 循环读取其 stdout。不这么写,脚本跑完就停了。
一个可靠模板:
#!/bin/bash
DIR="/data/inbox"
inotifywait -m -r -e create --format '%w%f' "$DIR" | while read FILE; do
# 注意:这里 $FILE 是完整路径,且可能含空格,务必加引号
if [ -f "$FILE" ]; then
echo "New file: $FILE"
# 在这里调用你的处理逻辑,比如:
# python3 /opt/process.py "$FILE"
fi
done
关键点:
-
--format '%w%f'确保输出完整路径,避免拼接出错 - 用
if [ -f "$FILE" ]过滤掉目录创建事件(create也会触发目录) - 管道后的
while在子 shell 中执行,若需在循环外用变量,得改用进程替换或临时文件
inotifywait 处理并发上传容易丢事件
当多个文件几乎同时写入(如 rsync 批量传、SFTP 多线程上传),inotifywait 默认每行只输出一个事件,但若写入速度极快,可能因缓冲或调度导致事件合并或丢失 —— 尤其是小文件密集写入场景。
缓解方式:
- 加
-q减少输出干扰,提升响应;加--buffer-size 65536增大内核事件队列(需内核支持) - 避免在
while循环里做耗时操作(如解压、转码),应把文件路径写入队列,另起守护进程消费 - 更稳的做法:用
inotifywait -m -e moved_to替代create,因为moved_to表示文件已写完(常见于 cp/rsync 完成后原子移动)
systemd 服务化需注意工作目录和权限
想让监听脚本开机自启,用 systemd 最稳妥,但容易踩两个坑:
- 脚本里用相对路径(如
./process.sh)会失败 ——systemd默认工作目录是/,必须用绝对路径,或在 service 文件中设WorkingDirectory= - 监听的目录若属其他用户(如
/var/www/uploads属 www-data),运行服务的用户(如user=daemon)必须有读+执行权限(execute对目录是进入权限) - 别忘了加
Restart=always和RestartSec=5,否则inotifywait异常退出后服务就挂了
复杂点在于:inotify 事件本身不区分“写入完成”,你得结合业务判断文件是否真正可用 —— 比如检查文件大小是否稳定、是否有 .tmp 后缀、或依赖上游传输协议的完成信号。这层逻辑没法靠工具自动补全。











