inotify是linux内核原生支持的文件监控机制,内核≥2.6.13即支持,无需轮询、事件驱动、实时高效;需调大max_user_watches(默认8192),inotifywait必须加-m持续监听,推荐用close_write而非modify,shell中避免while read管道陷阱,复杂逻辑应改用pyinotify。

inotify 是 Linux 内核原生支持的文件监控机制,不用轮询、不依赖用户态定时器、事件触发即达——只要内核版本 ≥ 2.6.13(2005 年起就默认启用),它就是你该用的第一选择。其他方案如 tail -F、auditd 或 rsync + cron 要么语义错位,要么开销高,要么配置重,不解决“实时响应文件变动”这个核心诉求。
确认 inotify 内核支持并调大 max_user_watches
inotifywait 启动失败或漏事件,八成卡在这一步。
- 先确认内核已启用:grep CONFIG_INOTIFY_USER /boot/config-$(uname -r),输出 CONFIG_INOTIFY_USER=y 才算合格
- 查当前限制:cat /proc/sys/fs/inotify/max_user_watches,若 ≤ 8192(默认值),监控含几十个子目录的路径就会丢事件
- 临时生效:sudo sysctl -w fs.inotify.max_user_watches=524288
- 永久生效:往 /etc/sysctl.conf 追加一行 fs.inotify.max_user_watches=524288,再运行 sudo sysctl -pinotifywait 命令必须带 -m 才能持续监听
inotifywait 默认是“单次模式”:触发一次事件就退出。脚本里漏掉 -m,看起来在跑,其实只监听了第一下。
- 正确写法:inotifywait -m -e close_write /path
- close_write 比 modify 更可靠:vim、rsync、logrotate 等工具常先写临时文件再原子 rename,modify 会反复触发,close_write 只在内容真正落盘后触发一次
- 若需递归监控子目录,加 -r,但注意每个子目录都消耗一个 watch,容易触达 max_user_watches 上限
- 避免不加 -e:默认会输出大量 IN_ACCESS(读操作)和 IN_OPEN(打开文件)事件,干扰主线逻辑
Shell 脚本中用 while read 捕获事件有严重陷阱
看似自然的写法:inotifywait -m -e create /dir | while read path event; do ...; done,实际会出问题:
- 管道右侧的 while 在子 shell 中执行,变量无法回传给父 shell
- 更关键的是:如果 do 块里执行耗时命令(比如 rsync 或 curl),下一条事件可能被 inotifywait 缓冲区填满或管道阻塞而丢弃
- 正确做法是让 inotifywait 单次触发、执行完动作、再进下一轮循环:
#!/bin/bash MONITOR_DIR="/tmp/watch" while true; do FILE=$(inotifywait -q -m -e create --format '%w%f' "$MONITOR_DIR" | head -n 1) [ -n "$FILE" ] && echo "New file: $FILE" >> /tmp/log done- 注意:脚本退出前应
killall inotifywait 或记录 PID 显式终止,否则残留进程会占用 inotify fd
需要路径过滤或状态保持时,改用 pyinotify
inotifywait 适合快速验证和简单响应;一旦涉及复杂逻辑,比如:
- 只监控 .log 文件但排除 .swp 和 ~ 备份
- 需要记住上次处理的文件名做去重或顺序判断
- 要同时监听多个目录并区分来源
就得换 pyinotify。它不是简单包装,而是完整封装了 inotify_add_watch、事件解析、watch 管理等细节。
- 安装:pip install pyinotify
- 关键点:用 rec=True 开启递归,用 mask=pyinotify.IN_CREATE | pyinotify.IN_MOVED_TO 组合事件,避免手动拼字符串
- 不要直接在 process_IN_CREATE 里做重 IO 操作,建议发消息到队列或写入 FIFO,由另一个进程消费,防止事件积压
inotify 的坑不在功能弱,而在边界条件太“硬”:内核参数、管道语义、事件语义差异、watch 数量爆炸——这些地方一松懈,监控就变成“偶尔工作”。











