ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

scp远程文件传输实操:SSH递归拉取与推送文件夹完整指南

scp远程文件传输实操:SSH递归拉取与推送文件夹完整指南 scp这个名字在很多人眼里已经有点“老古董”了——毕竟SSH登录早就普及网上也天天有人喊“scp已经被rsync取代了”“用sftp不香吗”。但你真正在运维、部署、同步服务器之间的文件时scp依然是我个人日常用得最多的命令之一。原因很简单scp基于SSH协议天然自带加密和认证不需要额外起服务端进程只要目标机器能SSH登录就能用它把文件推上去或者拉下来。这个“顺手”的属性让它成为远程文件传输里最稳、最快上手的工具。这篇文章就是为“想把服务器上的文件夹整个拉回本地”或者“把本地项目推到远端服务器”这类需求准备的。我会把scp的常用姿势、参数原理、文件夹递归传输的完整步骤、踩过的坑和排查思路全部写清楚最后再给你一套实在的替代方案和建议保证你看完能在自己的机器上直接照着操作。1. scp到底是个什么工具在动手敲命令之前先弄清楚scp的本质是什么这直接决定了后面你会怎么理解它的参数和报错。1.1 基于SSH的远程复制协议我每次跟新同事解释scp都会用一句话概括它就是“SSH版的cp”。平时我们本地复制文件用cp命令scp就是把这个复制动作放到网络上执行通讯过程完全走SSH通道。也就是说你不需要像ftp那样专门搭建一个FTP服务也不需要看得见摸得着的网络磁盘共享更不用管目标机器的操作系统是CentOS还是Ubuntu、是Windows还是macOS只要它能开一个SSH服务scp就能跟它打交道。实际落地的时候scp的传输过程分三步走本地执行scp命令指定源路径、目标路径和账号。scp借助SSH协议与远端机器握手完成身份认证。认证通过后把源文件读出并“流式”写入目标路径。因为全程加密用户账号、密码、文件内容在网络上是不可见的这比早年间流行的ftp明文传输要安全很多。这也是为什么这么多年过去scp依旧是跨服务器传输文件时最不容易翻车的工具之一。1.2 为什么选scp而不是sftp、rsync或者ftp很多刚接触运维的朋友会问既然有sftp、rsync为什么还要学scp我把它们的定位拆开来看你就明白选择逻辑了sftp是交互式工具适合手动浏览远端目录但脚本化批量操作不如scp直白。rsync讲究增量同步适合两个目录长期保持一致的场景但首次全量传输时配置步骤和参数颗粒度都更重。ftp是明文传输现在绝大部分安全要求高的服务器都已经禁用了不适合生产环境。scp非常简单直接一条命令完成“把A机器的文件搬到B机器”没有会话管理的负担也没有增量同步的各种复杂状态。这个“简单直接”就是scp的核心价值。你在临时传个包、拉个日志、从生产机器取一份配置文件的时候最不需要的就是花里胡哨的功能你需要的是马上能把文件弄过来的确定性。scp恰好就是为这个场景设计的。1.3 scp能做什么、不能做什么scp能做本地推送到远端上传远端拉取到本地下载任一端支持文件或目录目录用-r递归基于SSH密钥或密码认证scp不能做或者说它的短板不能自动增量每次都是全量覆盖不比较源和目标差异。中断不能续传传了一半断了就从头再来大文件尤其心疼。不支持断点续传和复杂调度虽然可以限带宽但没法“稍后重试”。明白这些局限你就不会拿着一把锤子到处找钉子了。确实rsync在很多场景下是比scp更好的选择但你得先把scp用熟理解它跟rsync的差异之后才知道什么时候该换工具。2. 最常用的scp命令姿势不管你是要推文件还是拉文件scp的命令结构都遵循一个核心骨架scp [选项] 源路径 目标路径这个骨架跟cp是一模一样的只是路径里多了“用户名主机”的前缀。想清楚“源在哪、目标在哪”命令就不会写反。下面我把最常见的四种场景拆开讲。2.1 推送上传单个文件把本地的test.tar.gz上传到服务器/data/backup目录命令scp ./test.tar.gz root192.168.1.100:/data/backup/分解一下./test.tar.gz本地源文件。root192.168.1.100目标服务器的用户名和IP。/data/backup/目标目录后面的斜杠表示“放到这个目录下保持原文件名”。第一次连接时系统会提示确认主机指纹输入yes然后会让你输入root的密码。之后就会看到类似于下面这样的传输进度条test.tar.gz 100% 120MB 31.5MB/s 00:04看到100%就说明传完了。如果你用的是带密钥认证的服务器密码那一步会自动跳过这也是scp在自动化脚本里特别好用的原因。注意目标路径写成/data/backup/带末尾斜杠表示“作为文件放进该目录”写成/data/backup/newname.tar.gz则表示“把文件另存为newname.tar.gz”。这个细节很多人会在传大文件时踩坑因为一旦目标路径是个不存在的目录名某些版本会直接把文件改成这个名字而不是新建目录。2.2 拉取下载单个文件反过来从服务器把/data/logs/app.log拉到本地当前目录用scp root192.168.1.100:/data/logs/app.log ./这里的./就是本地当前目录。同理你也可以写成./logs_new.log改名保存。这个命令非常适合“上服务器看一眼日志顺便拖一份下来”的场景。我平时排查线上问题时最常用的就是这种用法不用先登录进去cat花屏半天直接scp下来用IDE打开搜索。2.3 推送文件夹到远端假设你要把本地一个项目目录./web整体部署到服务器/var/www/如果直接写scp ./web root192.168.1.100:/var/www/大概率会报错或只传输目录本身却不递归内容。因为scp默认只处理单个文件文件夹必须加上递归选项-rscp -r ./web root192.168.1.100:/var/www/加上-r之后scp会递归遍历./web下的所有子目录和文件逐个传过去。传完之后目标服务器上会出现/var/www/web这个完整目录树。如果你想直接把web里的内容“倒进”/var/www/而不是套一层web目录那要这样写scp -r ./web/* root192.168.1.100:/var/www/注意通配符*是在本地Shell里展开的也就是说只有本地这个文件夹下的文件才会被匹配到配合目标路径/var/www/效果就是“把web下的内容直接铺到目标目录里”。这个方法我在部署前端dist目录时经常用非常顺手。2.4 拉取文件夹到本地核心需求这是本次最核心的需求——把远端的整个文件夹拉回本地。写法跟推送文件夹对称scp -r root192.168.1.100:/data/project/data ./backup这里-r必须保留否则目标是一个文件夹时scp会直接报错not a regular file。/data/project/data远端要拉取的源目录。./backup本地目标目录如果目录不存在scp会自动创建。执行后的效果本地./backup目录下会出现一个data目录里面完整包含远端/data/project/data的所有文件与子目录。如果你想“把远端data目录里的内容复制到本地backup目录里而不是嵌套一层data”那就加个通配符scp -r root192.168.1.100:/data/project/data/* ./backup/这两种写法的目录结构差异直接影响后续脚本对路径的假设分享一个我的切身体会如果不确定远端目录里有多少隐藏文件尽量先ssh过去ls -la看一眼因为*不匹配以点开头的隐藏文件。如果需要连隐藏文件一起拉就得用scp -r roothost:/data/project/data/./ ./backup/这种相对路径写法或者是干脆用rsync这个后面在进阶部分详细说。3. 关键参数与进阶配置scp如果不带任何参数也能用但你一旦接手批量、定时、跨跳板机的任务就得把这几个参数刻在脑子里。3.1 端口、密钥、密码等核心参数速查scp默认走SSH的22端口如果你改过端口或者通过跳板机转发就得指定-P参数。这里有一个新手最容易犯的错scp指定端口是大写-P而ssh本地端口转发是小写-p完全反过来的。每次写错都会提示Connection refused我当年被这个坑过不止一次。最常用的参数清单我做成了表格方便查阅参数作用示例-r递归复制目录scp -r ./dir roothost:/tmp/-P指定SSH端口大写scp -P 2222 file roothost:/tmp/-i指定私钥文件scp -i ~/.ssh/id_ed25519 file roothost:/tmp/-l限制带宽单位Kbit/sscp -l 1024 file roothost:/tmp/-C开启压缩传输scp -C big.sql roothost:/tmp/-p保留文件修改时间和权限小写scp -p file roothost:/tmp/-v显示调试信息scp -v file roothost:/tmp/-q关闭进度条scp -q file roothost:/tmp/-o透传SSH配置选项scp -o ConnectTimeout10 file roothost:/tmp/我单独说一下几个容易被忽略的-p小写默认情况下scp传过去的文件修改时间会被改成“传输完成那一刻”如果你需要保留原始时间戳比如备份日志或源代码包记得加-p。注意这里是小写p和大写P正好是端口参数一字之差含义天壤之别。-o ConnectTimeout10远程主机不可达时默认要卡很久才报错加这个参数可以在10秒内快速失败脚本里非常有用。-q配合定时任务或CI使用避免进程日志里刷一堆进度条。-C传文本类文件日志、源码、数据库dump时压缩效果明显但传已经压缩过的tar.gz、zip、jpg这类文件压缩只会白白消耗CPU务必别开。3.2 用SSH密钥免密传输密码登录虽然省事但是在脚本里硬编码密码既不安全又麻烦。scp本质走的是SSH认证所以配置好密钥之后scp直接就能免密工作。密钥配置三步本地生成密钥对如果还没有ssh-keygen -t ed25519 -C your_comment一路回车即可生成的公钥在~/.ssh/id_ed25519.pub。把公钥上传到目标服务器ssh-copy-id -i ~/.ssh/id_ed25519.pub root192.168.1.100这个命令会自动把公钥追加到远端~/.ssh/authorized_keys里免去手动编辑。验证ssh root192.168.1.100 echo ok如果直接输出ok说明免密生效。之后你再执行任意scp命令都不会被提示输密码了。密钥认证的好处不仅仅是方便更是安全。密钥本身的强度远高于你常用的口头密码而且你可以在服务器上通过修改authorized_keys来实现精细的访问控制比如只允许某些主机登录。3.3 跨跳板机传输的两种思路公司内网环境经常有“只能通过跳板机登录目标机器”的情况。这种网络下scp默认直连目标IP是连不通的我推荐两种解法。第一种使用ProxyJump参数让scp“自动先连跳板机再跳转到目标机”scp -o ProxyJumpjump_userjump_host -r ./app roottarget_host:/opt/app/这里的核心逻辑是-o ProxyJump让SSH先建立到跳板机的连接再由跳板机转发到目标主机。前提是跳板机本身能SSH到目标主机并且目标主机在内网可达。第二种本地做SSH端口转发把远端22端口映射到本地某个端口然后再scpssh -L 2222:target_host:22 jump_userjump_host -N这个命令会建立一条从本地2222端口到目标主机22端口的隧道然后再开一个终端scp -P 2222 ./app root127.0.0.1:/opt/app/路径上虽然绕了一圈但实际是通的。第一种写法更优雅适合经常配跳板机的人第二种适合临时应急、或者目标机只开放内网SSH端口而不允许直接外连的情况。无论用哪种都建议把常用参数写进~/.ssh/config这样scp命令会变得更短更整洁。4. scp拉取文件夹的完整实操记录理论知识铺完我直接给你一份完整的实操记录你可以照着敲一遍。假设现在我们要把一台业务服务器上的/srv/backup/2025全部拉回本地放在~/backup_restore/目录下。4.1 第一步确认远端目录结构先SSH上去看一眼避免拉下来发现目录结构不对ssh root192.168.1.100 ls -la /srv/backup/2025/[roothost ~]# ls -la /srv/backup/2025/ total 240 drwxr-xr-x 6 root root 4096 Jan 10 02:30 . drwxr-xr-x 8 root root 4096 Jan 10 02:30 .. -rw-r--r-- 1 root root 2310M Jan 10 02:30 app_db.sql.gz -rw-r--r-- 1 root root 890M Jan 10 02:30 user_data.tar.gz -rw-r--r-- 1 root root 120K Jan 10 02:30 config.yaml drwxr-xr-x 2 root root 4096 Jan 10 02:30 logs drwxr-xr-x 2 root root 4096 Jan 10 02:30 old_archives这一步特别关键你要知道源目录总大小、有没有隐藏文件、子目录层级。总大小决定了你要不要限速有没有隐藏文件决定了你要不要用特殊写法。4.2 第二步执行带-r的拉取命令回到本地终端执行mkdir -p ~/backup_restore scp -r -p root192.168.1.100:/srv/backup/2025 ~/backup_restore/看下我加了哪些参数-r递归目录-p保留文件原始时间戳和权限传输过程会逐个文件列出进度条。由于有3GB左右的数据如果网络是一般办公网可能得等几分钟。这时候我建议同时开-C吗不建议因为源文件都是.sql.gz和.tar.gz已经是压缩过的再压缩只会增大CPU开销。传输完的样子大致是app_db.sql.gz 100% 2310MB 24.8MB/s 01:33 user_data.tar.gz 100% 890MB 28.1MB/s 00:32 config.yaml 100% 120KB 105.6KB/s 00:01 ...4.3 第三步校验文件完整性scp本身不提供校验和功能所以在下载重要数据时我习惯在SSH登录时先记录源文件的md5或sha256传输完成后在本地再算一遍。大文件算md5比较慢可以用sha256或者只对关键文件做校验远端生成校验值ssh root192.168.1.100 md5sum /srv/backup/2025/app_db.sql.gz本地核对md5sum ~/backup_restore/2025/app_db.sql.gz两次结果一致就说明传输没有损坏。说实话scp走的是TCP加密通道数据在链路上出错的概率非常低但“非常低”不等于“零”备份数据多一道校验永远不吃亏。4.4 关于大目录传输的一个建议如果你要拉取的目录超过10GB或者里面是几十万个零碎小文件我建议你先在服务器上打包成一个tar文件再拉ssh root192.168.1.100 cd /srv/backup tar -czf 2025.tar.gz 2025 scp root192.168.1.100:/srv/backup/2025.tar.gz ./为什么这么干有几个理由大量小文件逐个传输时每个文件都有一轮SSH通道的握手开销和文件元数据操作整体耗时和CPU占用都很高。打包成一个单文件后传输速率会大幅提升因为TCP窗口能更好地利用带宽。单个文件更容易校验也更容易在远端做断点续传或者并行加速。这个技巧在几十G的日志收集、数据库备份迁移场景里尤其有用强烈建议试试。5. 高频问题与排查经验scp用久了总会碰到各种奇怪报错。这里我把过去踩过的坑按“最常见的先讲”总结成实战速查。5.1 Permission denied与认证失败报错定位Permission denied (publickey,password).这个报错出现时先别急着怀疑服务器拒绝了你。按我的排查顺序来过一遍用户名是否正确root用户和普通用户的权限范围完全不同。密码是否正确大写的注意别被Caps Lock坑了。如果用了密钥本地私钥路径是否跟-i参数一致服务器上的authorized_keys权限是否为600服务器sshd_config里是否开启了PasswordAuthentication yes如果服务器禁用了密码登录你只在命令行里输密码是永远不行的。针对第3点我有个血泪教训authorized_keys文件权限如果写成了644OpenSSH会直接忽略它怎么登录都失败。改成600即可chmod 600 ~/.ssh/authorized_keys chmod 700 ~/.ssh5.2 每次连接都卡很久才报错这个场景我遇到过很多次尤其是从本地跳转到公司内网机器时。大部分原因是目标IP不可达TCP连接超时天然要等很久。解决办法scp -o ConnectTimeout10 -o BatchModeyes ./file root192.168.1.100:/tmp/ConnectTimeout1010秒连不上就直接放弃。BatchModeyes禁止交互式输入密码防止CI脚本被卡在密码提示上直接挂死。如果还不行再排查是不是有防火墙或安全组拦截这个就得靠网络组配合了。5.3 scp断了不能续传怎么办scp没有续传功能传大文件时网络一旦抖动就前功尽弃。我的处理方案有三个优先打包成单个大文件后再传尽量避免成千上万小文件的场景。使用rsync --partial -P来做续传rsync的断点续传能力是真的稳唯一要求是目标端也装了rsync。如果必须用scp且网络极不稳定分批把大文件切成块传完再合并。切块合并的命令split -b 2G big_file.tar.gz part_ # 本地切 scp part_* roothost:/tmp/ # 分批传 ssh roothost cd /tmp cat part_* big_file.tar.gz # 远端合并这个方法比较土但确实能在网络条件很差的时候保证进度可控。5.4 端口、通配符和路径的“隐形坑”讲几个容易忽略的坑*通配符是本地Shell展开的如果你写roothost:/tmp/*本质上是想把远端所有文件拉下来但scp的路径展开规则可能导致结果不符合预期。更稳妥的做法是先ssh远端确认文件名再手动指定或者用-r直接拉目录。路径里有空格或特殊字符时记得对整个远端路径加引号scp roothost:/data/my dir/file.txt ./scp在执行时目标路径的目录如果不存在行为可能不同。比如目标/data/newdir/里的newdir原本不存在它不会自动创建这个目录层而是直接报错或产生错误的结构。所以传输目录之前最好先手动ssh host mkdir -p /data/newdir6. 使用场景延伸当scp不再是唯一选项对老手来说scp是“基本盘”但真正一到生产环境你会发现有些任务需要跟别的工具配合使用才舒服。这部分我分享几个真实场景和替代方案帮你把武器库补全。6.1 小文件海量场景rsync才是正解如果你的目录里有几万个图片、几百MB却由无数小文件组成scp的表现会让人崩溃。因为每个文件都要经历一次握手级别的开销整体速度会被严重拉低。rsync是增量同步工具首次可以慢慢全量之后每次只传差异部分。配合--delete --archive --progress使用能做到目录严丝合缝的镜像同步rsync -avz --delete --progress ./web/ roothost:/var/www/html/注意这里的源路径后面带/表示把目录里的内容同步过去而不是嵌套一层。rsync在同步方向上也更灵活支持双向镜像、远程到远程这是scp做不到的。6.2 定时备份与自动化脚本scp适合放在简单的定时任务里比如每天凌晨把当天的日志拉回本地归档。我常用的脚本大概长这样#!/bin/bash # 每天凌晨1点拉取昨日日志 YESTERDAY$(date -d yesterday %Y%m%d) scp -P 22 -i ~/.ssh/id_ed25519 -o ConnectTimeout10 \ root192.168.1.100:/data/logs/app_$YESTERDAY.log \ /backup/logs/三个关键点一定要用SSH密钥否则crontab里没法输密码一定要加-o ConnectTimeout避免网络异常导致脚本挂住日志如果比较多优先打包再拉否则凌晨的流量可能占用大量带宽。如果你要同步整目录且要求目录两端严格一致那就请rsync出马再配合锁文件防止并发执行已经很接近一套正式的备份方案了。6.3 和CI/CD结合发布部署的场景现在很多CI流程里构建完成后需要把产物分发到服务器。scp因为简单直接、依赖库少经常被用在Docker镜像或者部署脚本里。我见过很多项目在GitLab CI的job里就是用一条scp把jar包推到测试服务器再ssh过去重启服务。deploy: script: - scp -o StrictHostKeyCheckingno target/app.jar roottest-server:/opt/app/ - ssh roottest-server systemctl restart app这里加-o StrictHostKeyCheckingno是为了避免首次连接时交互式确认指纹卡住CI但生产环境务必保持默认严格校验别为了省事把安全检查也省了。6.4 现在到底该用scp还是rsync一个比较实用的判断标准临时传文件、单个文件、几十个文件以内、或者场景是一次性的本地上传/下载就用scp。目录要长期同步、数量成千上万、每天重复跑或者需要对标目录结构就用rsync。需要图形化操作、把远端目录挂在本地当磁盘用那就考虑sftp或sshfs。我在实际工作里的体会是scp做“即用即走”的临时任务非常省心rsync做“持续维护”的任务非常可靠。两者不是替代关系而是互补关系。作为新人先把scp悟透再学rsync你会发现rsync很多选项跟scp一脉相承过渡非常平滑。最后再分享一个我自己的小习惯。做运维这几年我用scp最多的场景不是专程传文件而是修机器的时候随手把远端配置拉下来改完再推回去。比如nginx配置、systemd服务文件一条scp拉到本地用熟悉的编辑器改完再scp推上去比在终端里用vim跟上百行的配置较劲舒服太多了。这个习惯让我在排查问题时少了很多无效登录、无效cat。另外我强烈建议你把常用主机的连接信息写进~/.ssh/configHost prod HostName 192.168.1.100 User root Port 22 IdentityFile ~/.ssh/id_ed25519之后scp命令可以直接写成scp ./file prod:/tmp/又短又不会打错IP。这个配置同样适用于ssh和rsync一劳永逸。scp这个工具本身不大但它的思想——所有网络传输都建立在SSH这条安全通道上——会一直延续到你对sftp、rsync、git、docker registry等更多工具的理解里。你现在把它用熟了以后接触更复杂的传输工具时会发现很多概念都是相通的。希望这篇实操分享能帮你在服务器之间搬文件时少走弯路多留点时间给真正有价值的调试和架构工作。
返回列表