inotify-tools监听文件系统事件需调大内核max_user_watches参数(默认8192,建议524288),否则易丢事件;安装推荐源码编译,使用inotifywait时须加-m持续监听、选close_write事件、脚本中校验文件就绪并防重入。

inotify-tools 能直接监听文件系统事件,不需要轮询,但默认内核参数极小,不调大就容易丢事件——这是你监控失效的最常见原因。
确认内核支持并检查默认限制
Linux 2.6.13+ 内核都支持 inotify,但默认参数太保守,max_user_watches 默认仅 8192,监控一个含几百个子目录的日志树就会溢出。
- 运行
ls -l /proc/sys/fs/inotify/,能看到max_queued_events、max_user_instances、max_user_watches三个文件才算支持 - 用
cat /proc/sys/fs/inotify/max_user_watches查当前值;如果低于 50000,大概率会漏报 - 临时调大:运行
sudo sysctl -w fs.inotify.max_user_watches=524288 - 永久生效:追加
fs.inotify.max_user_watches=524288到/etc/sysctl.conf,再执行sudo sysctl -p
安装 inotify-tools 的实际选择
包管理器安装最快,但版本可能旧(如 CentOS 7 自带 3.14);源码编译能拿到新功能(比如更稳定的 --excludei),但需提前装好 autoconf、automake、libtool。
- Debian/Ubuntu:
sudo apt install inotify-tools - RHEL/CentOS 8+:
sudo dnf install inotify-tools - 源码安装(推荐用于生产):
git clone https://gitcode.com/gh_mirrors/ino/inotify-tools && cd inotify-tools && ./autogen.sh && ./configure --prefix=/usr/local && make && sudo make install - 验证:
inotifywait --version输出带小数点的版本号(如4.23.9.0)即成功
inotifywait 常用命令组合避坑
inotifywait 是主力命令,但参数组合错一点,行为就完全不对——比如漏掉 -m 就只触发一次,-r 不配 -e 可能输出空行。
- 持续递归监听创建和修改:
inotifywait -m -r -e create,modify /path/to/watch - 过滤掉临时文件(如 vim 的
.swp):inotifywait -m -r -e create --excludei '\.swp$|~$' /path - 输出带时间戳的清晰格式:
inotifywait -m -r --format '%T %w%f %e' --timefmt '%Y-%m-%d %H:%M:%S' /path - 静默模式(脚本中常用):
inotifywait -q -m -e moved_to /path,避免干扰管道处理 - 注意:
close_write比modify更可靠——很多程序(如 rsync、logrotate)是先写临时文件再原子 rename,modify会反复触发,close_write只在写入完成时触发一次
写监控脚本时最关键的三件事
几乎所有失败的 inotify 脚本,都栽在这三点上:事件未完成就读取、并发触发多次、没做路径拼接校验。
- 用
--format '%w%f'而不是依赖read path action file分割,因为文件名含空格或特殊字符时会断开 - 检测文件是否真正就绪:
if [ -f "$file" ] && [ -s "$file" ]; then ... fi,避免读到零字节或正在写入的文件 - 加锁或 sleep 防重入:
inotifywait -m -e moved_to /path | while read file; do flock -n /tmp/monitor.lock -c 'do_something "$file"'; done,或简单加sleep 0.1 - 别把
inotifywait放在 while 循环里(如while true; do inotifywait ...; done),这会导致每次事件后重启进程,丢失上下文且增加开销
真正难的不是监听到事件,而是确保每次事件对应一个完整、可处理的文件状态。内核参数、事件类型选择、脚本健壮性,三者缺一不可——尤其 max_user_watches,它不像错误日志那样明显报错,只是悄悄丢事件。











