尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Linux文件传输工具详解:scp、ftp、wget与curl的差异与实战

Linux文件传输工具详解:scp、ftp、wget与curl的差异与实战 经常有读者在后台问我类似的问题我要把本地的文件传到服务器用 scp 还是 ftp我下载一个安装包wget 和 curl 到底有啥区别说实话我在刚接触 Linux 那阵也被这四个命令搞晕过——看起来都是传文件但实际工作方式、适用场景、底层协议完全不一样。这篇文章就不绕弯子直接把 scp、ftp、wget、curl 这四个工具讲透。我会从实际使用的角度出发讲清楚它们的语法、常用参数、适用场景以及我自己在真实环境中踩过的坑。不管你是刚入门 Linux 的新人还是已经写了好几年 shell 脚本的老手这篇文章都应该能帮你把这四个工具用得更顺手。1. 为什么Linux用户迟早要面对传文件这件事1.1 从一次真实的上线经历说起我印象特别深的一次经历刚接手一台服务器需要把本地写好的配置文件、打包好的代码压缩包传上去部署。当时我打开终端第一反应是用 Xshell 的拖拽上传结果传输到一半卡住不动了换成 rz 命令小文件还行一旦超过几百兆就直接失去响应。最后逼得没办法才老老实实打开了 scp 的官方手册。那次之后我彻底明白了一个道理在 Linux 环境下文件传输不是一个能传就行的问题而是一个在什么场景下、用什么协议、选哪个工具的决策问题。你面对的是几 MB 的配置文件还是几个 GB 的数据库备份对方是需要交互式操作的 FTP 服务器还是只要一条命令就能拉取文件的 HTTP 下载地址需求不同选型完全不同。1.2 四个工具的定位差异先搞清楚谁解决什么问题很多人把 scp、ftp、wget、curl 混为一谈默认它们都是下载/上传文件的命令这是最大的认知误区。我给这四个工具做个粗线条的定位scp是安全复制底层走的是 SSH 协议。它适合在你自己有账号权限的服务器之间传文件不需要额外搭建任何服务端只要目标机器开着 SSH 就行。ftp是文件传输协议里的正统军。它需要一台运行 FTP 服务端的机器适合做目录浏览、批量上传下载、多用户权限管理但默认是明文传输。wget是一个下载器。它针对的是 HTTP/HTTPS/FTP 的下载场景比如从软件源拉一个安装包、镜像整个网站目录它擅长递归、续传、后台下载这些东西。curl是一个传输工具它的能力边界比 wget 大得多。不只是下载还能发 POST 请求、带上请求头、模拟表单提交、上传文件、调试接口。很多后端同学把它当 API 测试工具用。先记住这个分工然后我们再逐个展开。你在实际使用中遇到的很多困惑其实都是用 A 工具干 B 工具该干的活造成的。2. scp基于SSH的安全文件复制服务器间传输的最稳选择2.1 scp基本语法与三种最常见用法scp 的全称是 secure copy它把文件复制建立在 SSH 加密通道之上所以安全性是天然的。它的基本语法和 cp 非常像只是多了远程主机这一维度scp [选项] 源路径 目标路径路径的写法规则是如果目标是远程机器就写成用户名主机地址:路径。我实际工作中最常用的就三种第一种本地推送到远程服务器scp ./app.tar.gz root192.168.1.100:/opt/deploy/这条命令把当前目录下的 app.tar.gz 复制到 192.168.1.100 这台机器的 /opt/deploy/ 目录下。执行后会提示输入 root 的 SSH 密码前提是你没有配置免密登录。第二种从远程服务器拉取到本地scp root192.168.1.100:/var/log/nginx/access.log ./logs/这个方向是反向操作把远程机器的日志文件拉回本地分析。我排查线上问题的时候经常用这一条。第三种两台远程服务器之间直接传输scp root192.168.1.100:/data/backup.sql root192.168.1.101:/data/注意这种写法有个细节数据是先经过你本机中转的不是两台服务器直接对接。如果两个服务器之间网络延迟很高中间再经过你本机速度会明显变慢。这时候更专业的做法是登录到其中一台服务器上再执行 scp让两台服务器之间直连。2.2 常用参数与免密配置scp 的参数不多但有几个必须记牢参数作用备注-P指定 SSH 端口大写 P因为小写 p 是保留时间戳-r递归复制整个目录复制目录必带-C传输时启用压缩传文本文件效果好传已压缩的 tar.gz 反而增加 CPU 开销-i指定私钥文件多密钥环境必备-l限制带宽单位是 Kbit/s注意不是 KB/s-p保留文件的修改时间和访问时间小写和 -P 含义完全不同我特别想提醒-P和-p的区别。有一次同事问我为什么 scp 指定端口一直报错我一看他写的是scp -p 2222 file userhost:/path这就是把-p当成端口参数了结果它把保留时间戳这个功能打开了端口反而用的默认 22。这个大小写问题坑了无数人。如果你的服务器 SSH 端口改成了 2222那么命令要写成scp -P 2222 ./file.tar.gz root192.168.1.100:/opt/实际工作中频繁输入密码很影响效率所以配置免密登录是标准操作。做法分两步第一步在本地生成密钥对第二步把公钥追加到远程机器的 authorized_keys 文件里。ssh-keygen -t ed25519 -C your_emailexample.com ssh-copy-id root192.168.1.100ssh-keygen生成密钥时一路回车即可默认生成到 ~/.ssh/ 目录下。ssh-copy-id是专门用来把公钥推送到远程的工具它会在远程创建 ~/.ssh/authorized_keys 文件并追加公钥整个过程自动化完成。配置好之后scp 和 ssh 都不需要再输密码了。2.3 scp的短板为什么它不适合做持续同步scp 虽然好用但它有一个硬伤不支持断点续传也没有增量同步的能力。假如你传一个 5GB 的文件传到 80% 的时候网络断了重新执行 scp 就得从头再来一遍。另外scp 每次都是全量复制不管目标路径下是否已经有相同的文件。你在本机改了一个 10MB 文件中的 1KBscp 也会把整个 10MB 都传过去。对于频繁更新、大量小文件的场景这个效率是很低的。所以我的个人习惯是一次性传送、服务器数量少、文件体积适中的场景用 scp如果是持续备份、目录同步这种需要增量传输的场景直接上 rsync。rsync 支持断点续传、增量同步、压缩传输还能通过 SSH 通道加密几乎是 scp 的完美替代品。scp 适合传一次就完事rsync 适合要长期保持两边目录一致。3. ftp老牌协议在批量管理场景下依然能打3.1 从客户端连接说起ftp与lftp很多人觉得 FTP 已经过时了其实在批量文件管理这个细分领域FTP 的生态依然非常成熟。比如企业内部的文件服务器、部分厂商设备的固件升级、网站旧版后台的文件管理很多还是基于 FTP。Linux 自带的 ftp 命令是一个最基础的交互式客户端连上服务器之后你会进入一个 ftp 提示符ftp 192.168.1.200连接成功后输入用户名密码就能用ls、cd、get、put这些命令操作了。get是下载单个文件put是上传单个文件。但 ftp 这个命令有个让人难受的地方不支持批量下载的通配符操作。你想下载当前目录下所有 .tar.gz 文件用mget *.tar.gz倒是可以但它会逐个文件询问你确认除非你先输入prompt off关闭交互确认。用起来总觉得不够痛快。所以我平时在命令行里操作 FTP更推荐用lftp。它是一个功能强大得多的 FTP/HTTP 客户端最吸引我的两点一是支持mget、mput批量操作且默认不啰嗦二是支持mirror目录镜像。看几个例子lftp -u username,password 192.168.1.200登录后输入mget *.tar.gz # 批量下载当前目录所有 tar.gz mput *.log # 批量上传本地所有 log 文件 mirror -c /remote/path /local/path # 镜像远程目录到本地支持断点续传mirror这个命令是我用 lftp 最大的原因。它可以把 FTP 服务器上的整个目录结构一次性同步到本地中途断了再执行还能续传等于是在 FTP 协议之上实现了一个简化版的 rsync 效果。3.2 主动模式与被动模式90%的FTP连不上都卡在这不管用哪个 FTP 客户端你迟早会碰到一个经典问题能登录成功执行ls也正常但一执行下载就卡住最后超时。这个问题十有八九出在主动模式和被动模式的选择上。FTP 协议和 HTTP 不一样它需要两条连接一条是控制连接默认 21 端口另一条是数据连接。主动模式下服务器主动去连接客户端的某个端口来传数据被动模式下服务器开放一个随机高端口由客户端主动去连。放在实际网络环境里如果客户端在 NAT 后面比如你本地电脑通过路由器上网主动模式基本是废的因为服务器没法主动穿透你的 NAT 去连你的内网端口。这时候必须切到被动模式。lftp 里可以这样设置set ftp:passive-mode onvsftpd 服务器端默认是开启被动模式的但很多云服务器厂商的安全组策略只放行了 21 端口导致被动模式的数据连接被防火墙拦死。这种情况需要在服务器端配置被动端口范围然后在防火墙和安全组里一并放行# /etc/vsftpd/vsftpd.conf pasv_enableYES pasv_min_port30000 pasv_max_port31000然后在防火墙放行firewall-cmd --permanent --add-port30000-31000/tcp firewall-cmd --reload每次排查 FTP 连接问题我都会按这个顺序走一遍先看控制连接通不通确认被动模式是否开启再检查数据端口是否被防火墙拦截。90% 的问题都能解决。3.3 用vsftpd快速搭一个本地测试服务如果你想自己动手验证 FTP 的各种操作一条命令在 Ubuntu/Debian 上就能装好 vsftpdapt update apt install -y vsftpd装完后修改 /etc/vsftpd.conf把匿名访问关掉允许本地用户登录anonymous_enableNO local_enableYES write_enableYES重启服务systemctl restart vsftpd这样你本机的系统用户就能通过 FTP 登录了。但要注意出于安全考虑默认配置下用户登录后只能访问自己的家目录这是 vsftpd 的 chroot 机制在起作用。如果你发现登录后看不到别的目录不用慌那是安全特性不是故障。说实话搭建 FTP 服务端在当前这个强调安全的环境里不算首选。如果只是临时给同事共享个文件我更推荐用 Python 一行命令起一个 HTTP 服务但如果你确实需要多用户、多目录、细粒度权限的共享方案FTP 依然是一个成熟可靠的选项。4. wget下载场景的瑞士军刀镜像站点的首选利器4.1 从单文件下载到批量下载wget 是 Linux 上最老牌的下载工具GNU 项目出品它的核心定位就是从网络上下载资源。最简单的用法wget https://mirrors.aliyun.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso默认情况下文件会下载到当前目录文件名保持服务器上的原始名称。但实际使用中我几乎不会用默认方式因为很多时候你不希望文件名被服务器那边随便定。这时候用-O参数指定输出文件名wget -O mylinux.iso https://mirrors.aliyun.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso-O还有另一个妙用配合-q安静模式可以静默下载并把内容输出到标准输出供管道使用wget -qO- https://example.com/version.txt | grep VERSION这在写自动化脚本时非常实用。比如启动一个服务前先动态获取最新版本的配置文件直接通过管道处理后写进目标路径全程不用落地临时文件。如果遇到一个网页里有大量附件需要批量下载可以先把所有链接提取出来配合 xargs 并行下载grep -o https://example.com/files/[^]* page.html | xargs -P 4 -I {} wget {}这里-P 4表示同时跑 4 个 wget 进程能明显提升下载速度但要注意别把对方服务器压垮。4.2 断点续传和限速下载大文件的保命技能下载大文件最怕什么怕下载到 50% 网络断了。重来一遍不仅浪费时间还可能因为对方服务器限速或者连接数限制导致永远下不完。wget 的-c参数就是为了这个场景准备的wget -c https://mirrors.aliyun.com/ubuntu-releases/22.04/ubuntu-22.04.4-desktop-amd64.iso-c表示 continue从上次中断的位置继续下载。这个功能实测非常可靠前提是服务器端支持断点续传HTTP 协议里对应 Range 请求头大部分下载站都支持。另一个容易忽略的参数是--limit-rate限速下载wget --limit-rate500k https://example.com/largefile.zip这个参数用的场景比较微妙。比如你在生产服务器上下载一个大文件但不希望下载占满所有带宽影响线上服务的正常响应限速就非常有用。我可以明确说一下这里的单位是字节/秒500k就是 512000 字节每秒。还有后台下载wget -b https://example.com/bigfile.iso命令加-b之后wget 会退到后台执行并把日志写到当前目录的 wget-log 文件里。你可以随时用tail -f wget-log查看下载进度。4.3 递归与镜像一键拉取整个站点的背后逻辑wget 最惊艳的能力是递归下载它可以把一个网站页面里引用的所有资源图片、CSS、JS、内部链接都抓下来实现离线浏览甚至整站镜像的效果。wget -r -l 3 -np https://docs.example.com/解释一下这几个参数-r开启递归下载。-l 3限制递归深度为 3 层防止无限深入。-np不上升到父目录避免把整个域名下的所有内容都拉下来。如果想做完整的镜像还有一个更省事的-m参数它等价于递归 无限深度 保留时间戳 不创建空目录的组合wget -m https://example.com/但要提醒一句镜像网站前务必确认你对目标站点有合法访问权限同时注意控制递归深度。我就见过有人递归下载一个技术文档站因为某个页面上有个返回首页的链接wget 顺着这个链接把全站几十万张图片全抓下来了硬盘直接塞满。如果某些文件你明确不需要可以用-R排除wget -r -np -R *.pdf,*.zip https://docs.example.com/这种精细控制能力是 wget 在下载工具中不可替代的原因。5. curl不只是下载工具更是API调试与协议测试利器5.1 curl与wget的本质区别curl 和 wget 在下载文件这件事上功能重叠但它们的核心设计理念完全不同。wget 的定位是下载器它关心的是怎么把资源完整地搞下来curl 的定位是传输工具它支持几十种协议HTTP、HTTPS、FTP、SFTP、SMTP、IMAP 等更关心的是怎么和协议交互。所以你在用 curl 时它默认把响应的内容输出到终端标准输出而不是直接存成文件。这种设计看似不友好实则是它最大的优势你可以直接看到返回内容配合管道做各种处理比如测试一个 API 接口curl https://api.example.com/users/123这条命令会直接打印出接口返回的 JSON 数据不需要落地成文件再去读。5.2 从GET到POST用curl完成一次接口调用我在日常工作中用 curl 最多的场景是调试 RESTful API。一个完整的 POST 请求通常长这样curl -X POST https://api.example.com/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}逐段拆解-X POST指定请求方法。不过大多数情况下可以不写因为-d参数会自动把请求变成 POST。-H添加请求头。这里声明了请求体是 JSON 格式。-d发送请求体数据。如果接口需要携带 Token那就再加一个请求头curl -X GET https://api.example.com/user/info \ -H Authorization: Bearer eyJhbGciOi...curl 还支持文件上传用-F模拟表单提交curl -X POST https://api.example.com/upload \ -F file/home/user/test.txt这里的符号后面跟本地文件路径非常直观。5.3 证书、重定向与上传curl绕不开的几个细节刚接触 curl 的人一般会碰到这几个问题。第一个问题访问 HTTPS 站点报证书错误。错误信息通常是curl: (60) SSL certificate problem。原因五花八门可能是服务器证书过期了可能是自签名证书也可能是本地 CA 证书库太旧。如果你确定对方站点是可信的可以临时加上-k参数跳过证书校验curl -k https://self-signed.example.com/但我要强调-k是排查问题时的临时手段不适合作为长期方案。跳过证书校验意味着中间人可以伪造服务器身份通信内容可以被窃取或篡改。更稳妥的做法是下载对方站点的 CA 证书然后用--cacert指定curl --cacert /path/to/ca.crt https://self-signed.example.com/第二个问题访问的 URL 发生了 301/302 跳转。有时候你请求的地址会自动跳转到另一个地址比如 http 跳转到 httpscurl 默认不会自动跟随跳转而是把 301 响应本身返回给你。要跟随跳转加-L参数curl -L https://example.com/download第三个问题把 curl 的输出接到流程里。前面说了curl 默认把内容打到标准输出所以它天然适合放进管道里。一个很经典的场景是下载并执行安装脚本curl -fsSL https://example.com/install.sh | bash这里的-f表示遇到 HTTP 错误比如 404时静默失败不要输出错误页面-s安静模式不显示进度条-S配合-s时出错时依然显示错误信息-L跟随重定向。直接把脚本通过管道交给 bash 执行一步到位。用这种方式时要对远程脚本的来源有信心最好先下载下来看一眼内容再执行。第四个问题接口响应太慢卡死在那里。给 curl 加上超时限制是基本素养curl --connect-timeout 5 --max-time 10 https://api.example.com--connect-timeout限制的是建立连接的时间--max-time限制整个请求的总时长。在脚本里调试 HTTP 接口这两个参数几乎是必加的能有效避免脚本因为网络问题而无限挂起。6. 四个工具放在一起到底怎么选6.1 一张表看清边界我把这四个工具的关键属性放在一张表里方便对比和查阅工具底层协议典型场景是否加密断点续传交互式操作需要服务端scpSSH服务器间文件复制、目录推送/拉取是否否仅需 SSH 服务ftp / lftpFTP批量上传下载、多用户文件共享否FTPS 可加密部分支持是需 FTP 服务端wgetHTTP/HTTPS/FTP下载安装包、镜像网站、递归抓取是HTTPS是否否curl几十种协议API 调试、表单提交、文件上传下载、协议测试是HTTPS是针对下载否否注意 ftp 这一行默认的 FTP 协议是明文传输如果传的是敏感数据建议换成 FTPSFTP over SSL或者直接用 SFTP。SFTP 也是基于 SSH 的和 scp 同源但交互能力更强支持断点续传和目录浏览。多说一句很多人把 SFTP 和 FTPS 搞混SFTP 是 SSH 协议家族的一部分FTPS 是 FTP 协议加了一层 SSL 加密二者完全不同。6.2 按实际场景的选型建议基于我自己的使用经验遇到具体需求时可以参考下面这套思路要把本地文件放到自己管理的服务器上首选 scp。简单直接只要目标机器能 SSH 登录就能用。如果文件特别大或者需要频繁同步换成 rsync。要和一台公共文件服务器交互对方明确给了 FTP 地址和账号用 lftp。它的 mirror 和批量操作能力能节省大量时间。需要从一个 URL 下载资源比如软件安装包、ISO 镜像、静态文件用 wget 或 curl 都行。我个人的习惯是简单下载用 wget因为参数更贴合下载场景需要看响应内容、调试接口或者上传文件时用 curl。需要测试后端接口、模拟 HTTP 请求、排查网络问题直接用 curl。它是这四个工具里唯一能精细控制请求方法、请求头、请求体的工具。有一个很常见的误区是很多人坚信 curl 能做的 wget 都能做或者反过来。实际上就算在下载这个交集场景里两者也有明显差异。wget 的递归下载能力是 curl 不具备的curl 需要配合其他工具才能实现递归而 curl 对协议的控制粒度、对请求头和请求体的精细操作wget 也做不到。所以不是谁替代谁的关系而是各管一摊。7. 实战中踩过的坑与排查经验7.1 scp提示host key验证失败有一次我重装了一台测试服务器的系统然后用 scp 连它结果报错 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!这是因为本机的 known_hosts 文件里还存着这台服务器的旧 SSH 指纹重装系统后指纹变了SSH 客户端为了防中间人攻击直接拒绝连接。解决办法不是把公钥删了重来而是先确认这台服务器确实是你熟悉的那台排除 DNS 劫持或网络中间人可能性然后移除旧指纹ssh-keygen -R 192.168.1.100之后再重新连接它会提示确认新的指纹输入 yes 就恢复正常了。这个命令很多新手不知道遇到指纹冲突就以为系统坏了其实一行ssh-keygen -R就解决。7.2 FTP文件名乱码从 Windows 那边的 FTP 服务器下载文件名带中文的文件经常出现乱码。原因在于 Windows 的 FTP 服务器默认用 GBK 编码传输文件名而 Linux 客户端默认按 UTF-8 解析。lftp 里可以设置远程编码set ftp:charset GBK set file:charset UTF-8这两行的意思是远程 FTP 服务端用 GBK 编码本地文件系统用 UTF-8。设置后再执行ls和mget文件名就正常了。这个问题特别隐蔽卡了我将近一个小时才搞明白分享出来希望看到的人少走弯路。7.3 wget递归下载导致的死循环有一回我想把一个在线文档站点拉下来离线阅读执行了wget -r -np https://docs.example.com/结果下载了一堆没用的页面——因为文档里引用了大量外部 CDN 资源而某些页面里又包含编辑本页这类指向外站的链接wget 顺着链接越抓越远。正确的做法是加-A参数限定只下载特定类型文件比如只下载 HTML 和图片wget -r -np -A *.html,*.jpg,*.png,*.css,*.js https://docs.example.com/另外--reject-regex可以根据正则排除外站链接例如wget -r -np --reject-regex (edit|login|logout) https://docs.example.com/在我后来长期维护离线文档的经验里递归下载之前先花两分钟理清链接关系整站镜像的成功率会高很多。7.4 curl的SSL证书报错我帮同事排查过一个有意思的问题服务器上 curl 访问某个接口一直报curl: (60) SSL certificate problem: unable to get local issuer certificate但浏览器访问同样的网址是正常的。这个问题的根源是服务器的 CA 证书库太旧缺少了信任该接口证书所需的根证书。解决方案不是甩一个-k上去而是更新系统的 CA 证书apt install --reinstall ca-certificates update-ca-certificates执行后再用 curl 访问就正常了。这个坑提醒我一件事遇到证书错误先别急着跳过校验先查一下是不是本地信任库本身的问题。-k是最后手段不是首选方案。还有一个相关的小技巧排查 HTTPS 接口问题的时候用curl -v可以打印完整的握手过程、请求头和响应头信息量远大于默认输出。加上-v之后你能看到 curl 使用了哪个 CA 证书、TLS 版本号、协商的加密套件定位问题会高效很多。这四个工具我几乎每天都在用。scp 是我部署服务器的手wget 是我拉取资源的嘴curl 是我调试接口的眼lftp 则是我处理批量文件时的仓库管理员。熟练使用它们并不难难的是在合适的场景选出合适的工具。希望这篇内容能让你少走一些我当初走过的弯路。
返回列表