inotifywait是最直接可靠的本地文件系统实时监控工具,支持ext4/xfs等主流类型,需加-m持续监听、-e指定事件(如modify),并注意递归监控时的watch句柄限制及不跨挂载点、不支持NFS等限制。

inotifywait 是最直接、可靠的方式,只要文件系统是本地 ext4/xfs 等主流类型,且你有读权限,就能实时捕获改动。轮询(如 find + stat)、tail -F 或 auditd 都不是默认推荐方案——前者不实时、后者太重或用途错位。
用 inotifywait 监控单个文件改动
这是 90% 场景的起点,比如盯住 /etc/hosts 或某个配置文件。
-
-m必须加,否则第一次修改就退出 -
-e modify显式指定,避免混入IN_ACCESS或IN_OPEN这类无关事件 - 输出带时间戳更易排查:加
--timefmt '%Y-%m-%d %H:%M:%S' --format '%T %w%f %e' - 示例命令:
inotifywait -m -e modify --format '%T %w%f %e' --timefmt '%Y-%m-%d %H:%M:%S' /etc/hosts
监控目录及子目录时递归与资源限制
想监看整个 /var/log/myapp 及其所有子目录?-r 是必需的,但会立刻暴露内核限制。
- 每个子目录都消耗一个 inotify watch 句柄,默认上限是
/proc/sys/fs/inotify/max_user_watches(通常 8192) - 递归监控几百个子目录就可能报
No space left on device——这不是磁盘满了,是句柄耗尽 - 临时调高:sudo sysctl -w fs.inotify.max_user_watches=524288
- 永久生效:echo 'fs.inotify.max_user_watches=524288' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
Shell 脚本里正确响应事件,别被管道坑了
很多人写成 inotifywait -m ... | while read line; do ...; done,这会导致事件丢失或变量失效。
- 管道右侧是子 shell,
read读到的变量在循环外不可见 - 更严重的是:如果
do块里执行耗时操作(如rsync、curl),下一条事件可能卡在管道缓冲区或被inotifywait丢弃 - 健壮写法是让
inotifywait单次触发,动作执行完再进下一轮:while inotifywait -e modify /path/to/file >/dev/null; do systemctl reload myservice; done - 若必须异步处理,用
&后台启动并忽略wait,但要确保不会堆积进程
为什么 inotifywait 查不到“谁改的”
它能告诉你“文件变了”,但无法回答“谁、用什么进程、以什么用户身份改的”——这不是 bug,是设计定位不同。
-
inotifywait工作在文件系统层,只感知事件,不抓取调用上下文 -
auditd才是查修改者的正解,但需提前部署规则(如sudo auditctl -w /path -p w -k myfile),且日志需用ausearch -k myfile -i解析 - 临时检查当前谁在写?可用
lsof +D /path或lsof /path/to/file,但这只反映“此刻打开中”,对已完成的写入无效
/mnt/nfs/config.yaml,inotifywait 会静默失败或根本无输出——这时得换 auditd 或服务端本地监控。


















