答案是使用inotifywait监听目录变动并精准触发rsync同步:脚本提取变更文件的最深一级目录,仅同步该子目录,避免全量同步;配合免密配置、日志分离、守护机制与充分验证,确保稳定高效。

用 Shell 实现监听目录变动并实时 rsync 同步到灾备机,核心是 inotifywait + rsync 组合,配合后台常驻和事件精准触发。关键不在“一气呵成”,而在避免重复同步、控制粒度、防止事件风暴和保障稳定性。
基础环境准备与验证
确保两台机器都满足前提:
- 生产机(源):内核 ≥ 2.6.13,已安装
inotify-tools(yum install -y inotify-tools)和rsync - 灾备机(目标):运行
rsync --daemon模式,配置好/etc/rsyncd.conf和密码文件(如/etc/rsyncd.secrets),权限设为600 - 生产机需有免密访问灾备机的 rsync 权限(通过
rsync_passwd_file指定,或使用 SSH 密钥对) - 确认网络互通,且灾备机 rsync 模块(如
[backup])已启用并允许生产机 IP 连接
监听+同步脚本(推荐最小粒度同步)
不建议监听整个大目录后全量 rsync —— 一次改 1 个文件就同步整个目录,效率极低。应提取变更路径,只同步受影响的最小单位(如某子目录)。
以下脚本监听 /data/www,当发生增删改时,解析出变更的最深一级目录(例如 /data/www/uploads/2026/07/abc.jpg → 同步 /data/www/uploads/2026/07/):
/opt/bin/inotify-rsync.sh,赋予可执行权限)#!/bin/bash
SRC="/data/www"
DST_MODULE="backup" # 灾备机 rsync 模块名
DST_HOST="192.168.250.18" # 灾备机 IP
RSYNC_USER="rsyncuser"
RSYNC_PASS="/etc/rsyncd/secrets"
<h1>切入源目录,保证 rsync -R 路径正确</h1><p>cd "$SRC" || exit 1</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/shouce/1785" title="Shell脚本编写基础 中文WORD版"><img
src="https://img.php.cn/upload/manual/000/000/016/170693311554316.png" alt="Shell脚本编写基础 中文WORD版" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/shouce/1785" title="Shell脚本编写基础 中文WORD版" class="overflowclass">Shell脚本编写基础 中文WORD版</a>
<p class="overflowclass">Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统</p>
</div>
<a rel="nofollow" href="/xiazai/shouce/1785" title="Shell脚本编写基础 中文WORD版" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>监听关键事件,排除临时文件和编辑器备份</h1><p>/usr/bin/inotifywait -mrq \
--format '%w%f %e' \
--event modify,create,delete,move,attrib,close_write \
--exclude '.(swp|swx|~)$' \
. | while read file event; do</p><h1>跳过空事件或无效路径</h1><p>[ -z "$file" ] && continue
[[ "$file" =~ ^/ ]] || continue</p><h1>提取变更发生的最深一级目录(如 /a/b/c/file → /a/b/c/)</h1><p>DIR=$(dirname "$file" | sed 's|^./||')</p><h1>若变更在根下(如 ./index.html),则同步整个 SRC</h1><p>[ "$DIR" = "." ] && DIR=""</p><h1>构造 rsync 源路径(带 trailing slash 保证内容复制)</h1><p>SYNC_SRC="${DIR:+$DIR/}"</p><h1>执行同步:-R 保留路径结构,--delete 删除目标端多余文件</h1><p>echo "[$(date '+%F %T')] Syncing $SYNC_SRC → $DST_HOST::$DST_MODULE" >> /var/log/inotify-rsync.log
export RSYNC_PASSWORD=$(cat "$RSYNC_PASS")
rsync -avzR --delete "$SYNC_SRC" "$RSYNC_USER@$DST_HOST::$DST_MODULE" 2>> /var/log/inotify-rsync.err
done</p>
后台持久运行与异常防护
脚本必须长期运行,同时防止单次失败阻塞后续事件:
- 用
nohup启动,并重定向输出:nohup /opt/bin/inotify-rsync.sh > /dev/null 2>&1 & - 加入简单守护逻辑(可选):写个 wrapper 脚本,每 5 分钟检查进程是否存在,不存在则重启
- 日志要分离:成功记录到
/var/log/inotify-rsync.log,错误单独进.err,方便排查 - 避免高频事件堆积:inotifywait 默认会缓冲事件,但若短时间大量操作(如解压千个文件),可在脚本开头加
sleep 0.1防止 rsync 并发冲突
调试与上线前必做检查
别跳过验证环节:
- 手动执行一次 rsync 命令,确认免密、模块名、路径、权限全部通
- 先去掉
-q和重定向,前台运行脚本,创建/修改/删除测试文件,看是否打印日志、是否触发 rsync - 检查灾备机目标目录权限,确保 rsync 用户有写入权;若用 daemon 模式,确认
read only = false在对应模块中已设置 - 用
ps aux | grep inotify和tail -f /var/log/inotify-rsync.log实时观察状态










