登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

rsync 目标目录不存在时怎么用 --mkpath 自动创建路径

来源:17golang原创

时间:2026-10-13 10:35:35 433浏览 收藏

首次把构建产物同步到新服务器时,最常见的阻塞不是文件不存在,而是远端目标路径还没有建好。rsync 可以用 --mkpath 自动创建目标路径中缺失的各级目录,最小写法如下:

# --mkpath 让接收端创建缺失的目标目录,源端末尾 / 表示同步目录内容
rsync -av --mkpath ./dist/ deploy@example.com:/srv/apps/releases/2026-10-13/

官方手册把它定义为创建目标路径中缺失的路径组件,语义接近在接收端执行 mkdir -p。它解决的是“目录链不存在”,并不会替远端账号获得父目录的遍历权或写权限。

官方地址:https://rsync.samba.org/ftp/rsync/rsync.1

记住三点:用 --mkpath 创建缺失目录,用目标末尾的 / 明确目录语义,再用远端实际登录用户检查父目录权限。权限不足时,继续添加参数也不会解决问题。

--mkpath 到底创建了什么

假设接收端原来只有 /srv,而 /srv/apps/releases/2026-10-13/ 整条路径都不存在。执行上面的目录同步命令时,rsync 会在接收端补齐缺少的 apps、releases 和 2026-10-13,然后把 dist/ 中的内容放进去。

这里的关键是“目标路径的缺失组件”,不是把源端的目录树原样复制到任意位置。--mkpath 只负责让目标路径可落地,文件是否更新仍然由 rsync 的同步规则决定。

rsync --mkpath 从源端到接收端逐级创建缺失目标目录的静态结构图
图1:rsync --mkpath 创建缺失目标路径的静态说明图,不是截图或运行证据。

目录同步时,两个斜杠要分清

目录同步最稳妥的写法是源路径和目标路径都保留末尾斜杠:

# 源端 dist/ 的内容进入目标目录,不额外包一层 dist
rsync -av --mkpath ./dist/ deploy@example.com:/srv/apps/releases/2026-10-13/

源端的 dist/ 表示“复制目录内容”;如果写成 ./dist,通常会把目录本身作为传输树的一层,结果可能变成目标下出现 dist/。目标端的末尾 / 则明确告诉 rsync:最后一段是目录,不要因为只有一个源项目而把它解释成目标文件名。

目标路径缺少中间目录时,--mkpath 才是本题的关键;单纯补一个目标末尾斜杠只能表达目录意图,不能替代创建缺失目录。

rsync 目录目标与单文件目标的末尾斜杠语义对比静态图
图2:目录目标、单文件目标与末尾斜杠关系的静态说明图,不是实际界面截图。

单个文件也可以直接落到新路径

部署脚本只上传一个归档文件时,可以把最终文件名写完整:

# 目标最后一段是文件名;--mkpath 负责创建它上面的父目录
rsync -av --mkpath ./build/app.tar.gz deploy@example.com:/srv/apps/releases/2026-10-13/app.tar.gz

这种写法的前提是源列表只有一个文件,并且目标最后一段不是已经存在的目录。若你的意图是把文件放进一个目录,而不是改名为某个文件,建议把目录写成带末尾斜杠的形式:

# 目录语义明确:文件名会保留在目标目录中
rsync -av --mkpath ./build/app.tar.gz deploy@example.com:/srv/apps/releases/2026-10-13/

权限报错时先看远端登录用户

--mkpath 创建目录的动作发生在接收端。远端 SSH 用户必须同时满足两个条件:

  • 能够逐级进入已经存在的父目录,也就是对路径上的目录拥有执行权限;
  • 对需要创建下一级目录的父目录拥有写权限。

因此,下面两条命令适合在远端排查目标路径的责任边界:

# 查看当前 SSH 用户,避免把本机账号误当成远端账号
id

# 从已有父目录开始检查是否能遍历并写入
namei -l /srv/apps/releases/2026-10-13

如果远端账号只能写入自己的发布目录,就把目标改到该账号拥有的目录;不要为了让 rsync 成功而直接扩大整棵目录树的权限。若目标位于受限目录,应该由管理员预先创建父目录并授予最小必要权限。

脚本里怎样保持首次运行和重复运行一致

把目标目录集中成一个变量,并始终使用同一条命令,可以避免首次运行时靠手工 ssh mkdir,后续又忘记同步参数:

#!/usr/bin/env bash
set -euo pipefail

# 统一发布目标,首次运行时由 --mkpath 创建缺失路径
target='deploy@example.com:/srv/apps/releases/2026-10-13/'

# 源端使用目录内容语义,重复运行仍由 rsync 判断需要更新的文件
rsync -av --mkpath ./dist/ "$target"

如果脚本需要让新建目录的属性尽量跟随发送端目录,而不是只创建一条可用路径,可以进一步研究官方手册提到的相对路径用法;但这已经是目录属性策略,不是 --mkpath 的基本职责。

常见误区速查

现象原因处理
中间目录不存在默认只会处理最终目标组件增加 --mkpath
目标多出一层 dist源路径没有使用内容语义目录内容同步时写成 dist/
文件被当成目录名或改名结果不对单文件目标的最后一段语义不明确目录目标加末尾 /,改名时写完整文件路径
Permission denied远端用户不能遍历或写入父目录用远端用户检查路径权限,预先准备最小权限

结论

rsync 目标目录不存在时,优先使用 --mkpath 处理多级路径创建;同步目录时保留源端和目标端的末尾斜杠,单文件上传时明确最终文件名。遇到权限错误,就回到接收端的登录用户、父目录遍历权和写权限,而不要把路径问题误判成传输参数问题。

相关问题

  • 为什么 rsync 加了 --mkpath 仍然提示 Permission denied?
  • 源目录后面的斜杠会不会改变远端最终目录层级?
  • 上传单个文件时,目标路径什么时候应该保留末尾斜杠?
  • 怎样确认 rsync 实际使用的是哪个远端账号?
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>