仅用rsync与POSIX shell脚本能否实现多客户端通过中心服务器同步?
仅用rsync + POSIX Shell实现多客户端与服务器的双向同步(含增删改)
你碰到的这个问题刚好是rsync单向同步特性带来的经典坑,但别担心——只用rsync加几行POSIX Shell脚本完全能搞定。核心思路是把同步拆成「拉取更新」「推送修改」「双向删同步」三个阶段,避开--delete选项的方向性冲突。下面是可直接落地的方案:
分步实现脚本
假设你的服务器路径是user@server:/main-storage/,客户端本地副本路径是./local-copy/,脚本可以这么写:
1. 先拉取服务器的更新到客户端(保留本地新增)
这一步只同步服务器的新增/修改文件,绝不删除客户端自己加的文件,避免客户端刚新增的内容被冲掉:
rsync -avz --no-delete user@server:/main-storage/ ./local-copy/
--no-delete:核心参数,禁用“删除客户端有但服务器没有的文件”的逻辑-avz:归档模式(保留权限、时间戳等元数据)+ 详细输出 + 压缩传输,是rsync同步的标准组合
2. 推送客户端的新增/修改到服务器
把客户端这边的新文件、改好的文件推送到服务器,同样不碰删除操作:
rsync -avz ./local-copy/ user@server:/main-storage/
这一步之后,服务器和客户端的「新增/修改内容」就完全一致了,接下来只需要处理两边的删除差异。
3. 同步双向的删除操作(关键步骤)
这一步要解决两个问题:客户端删了的文件要同步到服务器,服务器被其他客户端删了的文件要同步到客户端。我们用文件列表对比来精准定位要删的内容:
3.1 生成两边的文件列表(相对路径)
用POSIX兼容的find命令生成两边的文件路径(只保留相对于同步目录的路径,方便对比):
# 生成客户端本地文件列表 find ./local-copy/ -type f -printf "%P\n" | sort > client-files.txt # 生成服务器端文件列表(通过ssh远程执行) ssh user@server "find /main-storage/ -type f -printf '%P\n' | sort" > server-files.txt
如果你的系统find不支持-printf(比如某些极简嵌入式系统),可以替换成:
# 客户端列表替代写法 find ./local-copy/ -type f | sed 's|^./local-copy/||' | sort > client-files.txt # 服务器列表替代写法 ssh user@server "find /main-storage/ -type f | sed 's|^/main-storage/||' | sort" > server-files.txt
3.2 找出需要删除的文件
用comm命令对比两个列表,分别找出两边的冗余文件:
# 服务器有但客户端没有的文件 → 需要从服务器删除(客户端已删) comm -23 server-files.txt client-files.txt > delete-from-server.txt # 客户端有但服务器没有的文件 → 需要从客户端删除(其他客户端已删) comm -13 server-files.txt client-files.txt > delete-from-client.txt
3.3 执行删除
只在有需要删除的文件时执行操作,避免空命令报错:
# 删除服务器上的冗余文件 if [ -s delete-from-server.txt ]; then ssh user@server "cd /main-storage/ && xargs rm -f < /dev/stdin" < delete-from-server.txt fi # 删除客户端上的冗余文件 if [ -s delete-from-client.txt ]; then cd ./local-copy/ && xargs rm -f < ../delete-from-client.txt fi
3.4 清理临时文件
rm -f client-files.txt server-files.txt delete-from-server.txt delete-from-client.txt
方案说明与注意事项
- 为什么这个方案能解决问题?:我们把「增改同步」和「删除同步」完全分开,先确保两边的新增/修改内容完全对齐,再通过精准的文件列表对比来处理删除,彻底避开了
rsync --delete的方向性矛盾——不会出现先拉取删本地新增,或者先推送删服务器上其他客户端内容的问题。 - 处理目录删除:上面的脚本只处理了文件,如果需要同步目录的删除,把
find命令里的-type f去掉即可,删除时把rm -f改成rm -rf(注意:删除目录风险更高,建议先在测试环境验证)。 - 并发同步的小问题:如果多个客户端同时执行同步,可能会出现短暂的不一致,但因为是定期执行,下一次同步会自动修正,不会有永久冲突。
- 简化版风险提示:有人会想到用
rsync --delete-after先拉再推,但这种方式会删除客户端的新增文件,完全不适合你的场景,千万别用。
内容的提问来源于stack exchange,提问作者Mecki
相关产品推荐
相关产品推荐

