rsync 同步报 “some files could not be transferred” 的权限/时间戳坑

15次阅读

rsync报“some files could not be transferred”是因权限、时间戳等元数据操作失败导致的非零退出码,具体错误需通过重定向stderr或使用-i/–itemize-changes定位;常见原因包括NFS/docker卷不支持utimensat()、挂载限制、ACL/UID不匹配等,应针对性禁用–times/–perms或调整挂载参数。

rsync 同步报 “some files could not be transferred” 的权限/时间戳坑red” 却没说具体哪个文件失败

这是 rsync 的默认静默行为:只要任意一个文件因权限、只读挂载、时间戳设置失败等原因跳过,它就返回非零退出码并输出这句笼统提示,--verbose 也不一定显示细节。真正有用的线索藏在 stderr 里,但默认被忽略或混在大量输出中。

实操建议:

  • -v(或 --verbose)是基础,但还不够;必须重定向 stderr 才能看到真实错误,例如:rsync -av src/ dst/ 2>&1 | grep -E "(Permission denied|Operation not permitted|Failed to set times)"
  • --itemize-changes(简写 -i)能逐文件标出哪些属性同步失败(比如 .f……. 表示时间戳没设上,.p……. 表示权限没改成功)
  • 若目标是 NFS 或某些容器卷,--omit-dir-times--no-perms 可先绕过问题定位主因

“Operation not permitted” 设置时间戳失败的常见场景

这不是 rsync 本身的问题,而是目标文件系统不支持 utimensat() 或内核禁止普通用户修改 mtime/ctime。典型环境包括:Docker volume、rootless podman、某些挂载参数的 NFS、以及 macOS 上通过 SMB 挂载的共享目录。

实操建议:

  • 确认是否真需要精确时间戳:--times(默认启用)可改为 --no-times;若只需保留源文件的修改时间做参考,用 --copy-dest + --ignore-times 更稳妥
  • 若必须保留时间戳,检查目标挂载选项:NFS 需含 noac 或服务端开启 no_wdelaylinux 上可临时测试 touch -d @$(stat -c '%Y' somefile) /path/to/test 看是否报错
  • 避免在 rsync 命令里混用 --archive(隐含 --times)和手动加 --no-times,优先用显式开关控制

Permission denied 写入或 chmod 失败的根源判断

rsync 默认尝试还原源文件的权限(--perms),但目标位置可能:① 文件系统挂载为 noexec,nosuid,nodevro;② 目标目录 sticky bit 或 ACL 限制了 chmod;③ 源文件属主 UID 在目标机器不存在,导致 chown 失败(即使你没加 --owner--archive 也会触发)。

实操建议:

  • ls -ld /target/dir 确认挂载参数和目录权限;mount | grep $(df . | tail -1 | awk '{print $1}') 查看实际挂载选项
  • 明确关闭不需要的操作:--no-perms(跳过 chmod)、--no-owner(跳过 chown)、--no-group(跳过 chgrp)
  • 若需保留权限但目标不支持完整模式(如 FAT32),可用 --chmod=ugo=rwX 统一修正,而非依赖源文件原始 mode

为什么加了 --force 还是报错?

--force 只影响“删除目标上存在但源没有的文件”,跟权限或时间戳失败完全无关。很多人误以为它能强制覆盖权限限制,其实不能。真正相关的是 --ignore-errors——但它会让 rsync 忽略所有错误(包括磁盘满、网络断开),风险极大,不推荐用于生产同步。

更安全的做法:

  • 分两步走:先用 rsync -av --no-times --no-perms src/ dst/ 完成内容同步;再单独用 find dst/ -type f -exec touch -r {} {} ; 2>/dev/NULL 批量更新时间戳(仅限需要时)
  • 对关键任务,用 rsync --dry-run-i 预检,比硬着头皮跑完再查日志高效得多
  • 如果目标是远程服务器且你有 sudo 权限,考虑用 --rsync-path="sudo rsync",但务必确认远端 sudoers 允许无密码执行 rsync

最常被忽略的一点:rsync 的 exit code 是累计值——哪怕只有 1 个文件时间戳没设上,它也返回 24;而很多自动化脚本只检查 0/非0,根本意识不到“同步完成但部分元数据丢失”。别只看成功与否,得看 rsync 到底改了什么、没改什么。

text=ZqhQzanResources