rsync --files-from 报路径不存在:清单路径又被拼到源目录下
rsync 的 files-from 清单以源目录为根;修正重复前缀,先预演名单,再单独判断符号链接与递归范围,避免误覆盖。
把 find 的输出交给 rsync 的 --files-from 后,文件明明存在,却报 link_stat ... No such file or directory。仔细看报错路径,如果源目录的某段出现了两次,先核对清单里的路径是相对于哪里,而不是立刻改文件权限。
--files-from 读入的名称以 rsync 命令指定的源目录为根。清单不是任意绝对路径的集合;开头的 / 会被去掉,也不会因为清单写了完整绝对路径,就覆盖命令中的源目录。
把清单与源根放在一起看
假设实际文件是:
/srv/source/reports/a.csv
命令源目录为 /srv/source/ 时,清单应写:
reports/a.csv
如果清单却写成 /srv/source/reports/a.csv,rsync 会按源根继续定位,可能尝试访问 /srv/source/srv/source/reports/a.csv。这种重复前缀就是输入基准不一致的线索。去掉命令源路径末尾的斜杠,不会把清单变成任意绝对路径输入。
不要直接删掉所有清单路径的第一段。先确认清单生成位置、源根和期望保留的子目录层级;不同目录生成的名单可能需要不同处理。
固定源根,先用一条文件预演
下面假定 /srv/backup/ 是已存在的目标目录,/path/to/file-list.txt 是操作者准备的清单文件,两者均为占位路径。先只放入已核对的 reports/a.csv,再预演:
rsync -ani --files-from=/path/to/file-list.txt -- /srv/source/ /srv/backup/
-n 不实际同步,-i 显示计划变更。核对预期目标是否为 /srv/backup/reports/a.csv,并观察是否还出现重复前缀或其他不存在的路径。目标已有同名文件时,也要判断正式操作会不会覆盖需要保留的数据。
若清单由 find 生成,可以在源根中生成相对名称。以下只收集普通文件,使用 NUL 分隔以避免文件名中的换行造成拆分;输出文件应放在源树之外:
(
cd /srv/source || exit 1
find . -type f -print0
) > /path/to/file-list.nul
先确认生成命令成功、没有权限或遍历错误,再使用清单。上面的重定向会覆盖同名清单文件,需选择专用路径并保存旧清单;它不会修改源文件。不要在扫描失败后把不完整名单当作完整备份范围。
rsync -ani --from0 --files-from=/path/to/file-list.nul -- /srv/source/ /srv/backup/
这里的 ./reports/a.csv 与源根配套。--from0 必须与生成端的 -print0 一起使用;不能把普通逐行清单和 NUL 清单混用。
符号链接与目录递归是另外两个选择
如果原来收集的是 find ... -type l,目标又要求保存链接指向的内容,那么修好路径后还需决定是否使用 -L。它会跟随发送端符号链接,把所指文件或目录纳入传输;断链会报错,链接还可能指向源树之外。不要因为清单里只有源树内的链接名,就认为内容范围也被限制在源树内。
归档模式 -a 默认保留符号链接本身;-L 改变的是这个行为,与清单路径的基准没有关系。必须先审核链接目标及权限,才能决定是否读取那些内容。上面的普通文件示例没有加入 -L,也不负责收集符号链接。
使用 --files-from 时,-a 不再隐含 -r。如果只列目录却希望递归传输全部内容,要另行明确递归范围;本例逐项列出普通文件,不需要为了清单的父目录而盲目扩大递归。清单路径所需的中间目录会按 files-from 的规则保留。
真正写入前保存目标与参数
预演范围正确后,保存清单、源根、目标路径和选项,并准备目标数据的可恢复备份。正式同步只移除同一条命令中的 -n,其他经过检查的参数保持一致。归档模式还会尝试保留多种属性,实际效果受执行用户权限影响。
不要为排除这条路径错误追加 --delete。修正路径并不需要删除目标独有文件;目标删除范围应作为另外的需求审核。预演和真实同步之间源文件可能变化,应用数据还应使用一致快照或符合应用要求的备份方式。
同步后检查几个已知文件的完整目标路径、内容和必要属性,源稳定时再按同样选项预演,确认没有反复出现意外变更。若已覆盖了目标文件,改回清单不会恢复旧内容;应从同步前的备份恢复对应范围。


