rsync 升级后远程路径多了引号,报 change_dir 失败
rsync3.2.4开始保护远端参数,变量内额外引号可能成为真实路径字符。修正路径值与本地引用,审慎评估old-args和受限shell。
rsync 脚本在旧版本可以同步,升级到 3.2.4 后却出现 change_dir 和 No such file or directory。目标原本是绝对路径,报错中却出现远端用户的主目录,或额外的引号。先查看传给 rsync 的实际目标参数:脚本可能在变量值里保存了用于旧式远端 shell 解析的引号。
从 3.2.4 开始,默认的远端参数保护会转义空格等 shell 活跃字符。过去被远端 shell 去掉的引号,可能因此作为路径本身的字符保留下来。这不意味着绝对路径规则变了,也不意味着本地调用中的双引号都应该删除。
变量保存路径,调用处引用变量
下面是容易出错的 Bash 变量值:
target='operator@server.example.net:"/srv/backup"'
外层单引号用于本地 shell 解析,赋值完成后不在变量里;内层双引号却保存在值中。再以 "$target" 调用,rsync 收到的目标仍然含有这些双引号。
如果实际目录叫 /srv/backup,变量应保存真实路径,不再存一段需要 shell 重新解释的引用语法。带空格的示例为:
source='/srv/source'
target='operator@server.example.net:/srv/backup snapshots'
rsync -ani -- "$source/" "$target/"
主机、用户和目录均需替换,目标目录应事先存在或按既有流程建立。示例 -n 只预演,-i 显示变更;真正同步会覆盖目标同名内容并尝试保留归档属性,先确认范围与可恢复副本。不要为处理引号增加删除选项,也应保留既有 SSH 主机身份校验。
本地的 "$source/"、"$target/" 保持一个参数的边界,需要保留。选项若原本使用 Bash 数组,也继续按数组元素传递,不要拼接为一整条字符串后交给 eval。
如果真实文件名本来就含引号,不能用批量去引号的方法清洗路径。应比较变量中的每个字符与远端目录的实际名称,区分引用语法残留和合法文件名。
old-args 会改变保护规则
--old-args 可以让需要旧式远端参数重解释的脚本临时使用旧行为,但它关闭了默认参数保护,还会关闭用于防止远端发送额外顶层文件的检查。它不适合成为所有同步任务的默认设置。
排查时也要查看 RSYNC_OLD_ARGS 等环境是否影响实际行为。确认某个脚本确实依赖旧规则后,再限定兼容范围,并逐个修正参数生成方式;不要无记录地全局切换,让不同任务接受不同的路径解释。
需要绕过远端 shell 对大部分选项与文件名的解析时,可以评估 -s。当前名称是 --secluded-args,较早版本称 --protect-args。它要求远端 rsync 至少为 3.0.0,并可能被需要审查命令参数的受限 shell 拒绝。仍应传递实际文件名,不能指望它把变量里的多余引号重新当成语法去掉。
按远端最终路径验收
记录两端版本、脚本使用的 shell、实际参数值和目标目录,先用原同步范围预演。确认 rsync 定位到预期的绝对目录,含空格的路径没有被拆分,且计划变更没有扩大范围,才进入正式同步。
如果报的是 protocol version mismatch -- is your shell clean?,并在协议开始前出现欢迎语,应检查 远端启动脚本输出污染协议。去掉额外路径引号不能清理协议流中的文本,清理 .bashrc 也不能修正已经含有错误字符的目标参数。


