多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Linux服务器命令行操作百度网盘:bypy与BaiduPCS-Go实战

Linux服务器命令行操作百度网盘:bypy与BaiduPCS-Go实战 服务器上跑着一套日志归档脚本凌晨三点把几百兆的 gzip 包压好接下来怎么办总不能装个桌面环境开 VNC 去拖文件。我第一次撞上这个场景是给一台 Ubuntu 20.04 的跑批机器做异地备份那台机器只有 2G 内存装图形界面等于自寻死路。后来折腾出一套纯命令行的百度网盘操作方案主力是bypy和BaiduPCS-Go这两个工具上传、下载、目录同步、定时任务全都跑通了稳定跑了两年多。这篇就把整个 Linux/Ubuntu 服务器命令行使用百度网盘的过程摊开讲包括工具选型、授权流程、参数调优、踩过的坑和现成的自动化脚本适合手上有云服务器、需要把文件丢到百度网盘的运维和开发同学零基础也能照着抄。1. 先想清楚服务器上为什么要用命令行碰网盘1.1 服务器场景下真正在传的东西是什么很多人以为服务器传网盘就是下个文件实际上生产环境里的需求要杂得多。我整理了一下自己经手过的几类日志归档Nginx 的 access.log 按天切割压缩后每天 200MB 到 2GB 不等本地磁盘只有 40G必须定期外迁。数据库逻辑备份mysqldump 出来的 sql.gz一般不大但要求保留 30 天以上本地放不下。训练数据集与模型权重跑完一次训练存个 checkpoint动辄几个 G团队里其他人要用的时候直接从网盘拉。构建产物分发内网构建机编译出来的安装包几台测试机要同时下载同一个版本。一次性大文件中转客户丢过来一个 8G 的日志包得先落到服务器上再解压分析。这些需求的共同点是无人值守、机器没有桌面、带宽和内存都紧张。这就决定了方案必须是命令行的而且要能塞进 crontab 或者 systemd timer 里跑。判断一个工具合不合适我会看四条能不能非交互式授权、能不能断点续传、能不能只传增量、出错时退出码是不是规范。前三条决定它能不能干活第四条决定它能不能被监控系统感知到。1.2 命令行方案和网页端的本质差异网页端上传走的是浏览器的分片上传协议命令行工具走的是开放 API。这两条路在行为上有几个明显区别理解了之后很多玄学问题就说得通了。第一API 有调用频率限制。网页端你点一下就是一个用户操作服务端不太在意但脚本一秒钟调十次 list 接口就会被限流返回 31064 之类的错误码。所以命令行工具做目录遍历一定要加节流。第二默认目录不一样。网页端你的根目录就是/但第三方应用走 API 时默认被限制在/apps/应用名/这个沙箱目录里。bypy 默认操作的是/apps/bypy很多人第一次用完bypy list发现文件呢就是因为没去网页端的我的应用数据里找。这个坑我在第 5 节还会细说。第三带宽策略不同。命令行工具拿到的下载带宽和网页端、客户端是一致的非会员状态下都会受到限制这是服务方的商业策略不是工具的问题。我个人的做法是把大文件压缩到最小、只传增量、避开网络高峰时段用合理手段把效率做上去而不是指望工具能变出带宽来。第四失败重试的语义不同。网页端失败了会弹窗让你点命令行工具失败了只能靠退出码。所以脚本里必须显式处理返回值否则你会在三个月后才发现备份已经断了半年。1.3 工具选型bypy、BaiduPCS-Go 和 rclone 怎么挑目前在一台 Linux 服务器上操作百度网盘主流就三条路各自的定位差别挺大工具语言授权方式优势短板适合场景bypyPythonOAuth 授权码安装简单命令语义清晰支持 syncup/syncdown大文件上传偶发卡住需要手动重试中小文件、目录同步、定时备份BaiduPCS-GoGo账号凭证登录单文件二进制无依赖并发下载体验好登录方式涉及账号凭证安全性要自己把控大文件下载、单机快速取文件rcloneGo需自行申请应用凭证通用性强一个工具管多种存储百度网盘后端的配置门槛高多云统一管理的团队我自己的组合是日常目录同步和定时备份用 bypy临时要拉单个大文件用 BaiduPCS-Go。理由是 bypy 的syncup/syncdown语义非常接近 rsync写脚本时心智负担低而 BaiduPCS-Go 在处理大文件时的重试逻辑更稳而且它是静态编译的单一二进制丢到任何一台 x86 或者 arm64 的机器上都能直接跑不用管 Python 版本。如果你已经在用 rclone 管 S3、WebDAV 这些东西那统一到 rclone 也合理但要提前知道百度网盘后端需要你自己去申请开发者凭证并配置第一次折腾大概要花一两个小时不如前两个工具开箱即用。提示无论选哪个工具都要先想清楚一件事——这是备份还是同步同步会删除对端没有的文件备份不会。这个区别决定了你该不用sync类命令还是放心用。我见过有人拿同步命令做备份结果本地误删一个目录网盘上的也跟着没了。2. 动手前的环境准备与依赖梳理2.1 基础环境检查Python、pip 和系统时区先用三条命令把家底摸清楚避免后面装到一半发现版本不对# 看系统版本和内核 cat /etc/os-release uname -m # 看 Python 版本bypy 需要 Python 3 python3 --version # 看 pip 是否可用 python3 -m pip --version # 看时区和时间是否同步 timedatectl statusUbuntu 20.04 及以上自带 Python 3.8直接能用。如果你在用的是更老的发行版或者精简过的镜像可能只有 Python 2那就先装 Python 3 和 pipsudo apt update sudo apt install -y python3 python3-pip python3-dev ca-certificatesca-certificates这个包经常被忽略但它是必须的。所有百度网盘的 API 请求都走 HTTPS如果系统根证书不全会出现 SSL 证书验证失败报错信息还特别隐晦。我有一台从最小化镜像装起来的服务器就栽在这儿排查了四十分钟才想起来是证书包没装。时区也要顺手确认。timedatectl status里如果显示System clock synchronized: no就装个 chrony 或者 systemd-timesyncd 把时间同步打开sudo apt install -y systemd-timesyncd sudo systemctl enable --now systemd-timesyncd为什么时间这么重要因为 OAuth 授权流程里带时间戳和令牌有效期服务器时间偏差超过几分钟授权就会莫名其妙失败而且错误提示不会告诉你是时间不对。2.2 用虚拟环境隔离依赖我强烈建议不要直接pip install bypy装到系统环境里。Ubuntu 从 23.04 开始默认启用 PEP 668系统 pip 会直接拒绝安装就算能装将来系统包管理和 pip 包管理打架也够你受的。干净的做法是建一个专门的虚拟环境# 安装 venv 支持 sudo apt install -y python3-venv # 在家目录建一个专门跑网盘任务的环境 python3 -m venv ~/venv/netdisk source ~/venv/netdisk/bin/activate # 升级 pip换成国内源会快很多 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip pip install -i https://pypi.tuna.tsinghua.edu.cn/simple bypy装完之后which bypy应该指向~/venv/netdisk/bin/bypy。这个绝对路径很重要后面写 crontab 的时候必须用它因为 cron 执行时不会激活虚拟环境。如果你只是想临时用一下也可以把虚拟环境的 bin 目录软链到/usr/local/binsudo ln -sf ~/venv/netdisk/bin/bypy /usr/local/bin/bypy但要注意软链解决的是能找到命令解决不了能找到 Python 解释器和依赖库所以更稳的做法还是在脚本里显式写全路径。2.3 BaiduPCS-Go 的安装路径BaiduPCS-Go 是静态编译的省心得多。去它的发布页面对照架构下载对应压缩包x86_64 服务器选linux-amd64ARM 服务器选linux-arm64。假设你已经把压缩包传到了服务器上mkdir -p ~/tools cd ~/tools tar -zxvf BaiduPCS-Go-*.tar.gz mv BaiduPCS-Go-*-linux-amd64 BaiduPCS-Go chmod x BaiduPCS-Go sudo ln -sf ~/tools/BaiduPCS-Go /usr/local/bin/BaiduPCS-Go BaiduPCS-Go --version因为它是二进制不依赖 Python 环境所以放在/usr/local/bin之后系统里任何用户、任何 cron 任务都能直接调用这一点比 bypy 友好。注意这类第三方工具通过账号凭证调用官方接口属于个人开发者的开源项目。使用前建议通读一遍它的说明文档了解它会把凭证存在哪里一般在~/.config/BaiduPCS-Go/下并且只用在自己有权限的账号上。生产环境的服务器上尽量用一个专门的账号不要拿主力账号去跑脚本。3. 核心命令实操从授权到跑通第一条传输3.1 bypy 的授权流程走一遍就懂了首次运行任意 bypy 命令它都会引导你完成授权。整个过程是这样的source ~/venv/netdisk/bin/activate bypy info终端会打印一行类似这样的内容Please visit: https://openapi.baidu.com/oauth/2.0/authorize?client_id...response_typecode... And authorize this app Paste the Authorization Code here within 10 minutes.这时候把那个长链接复制到你自己电脑的浏览器里打开不是服务器上服务器没浏览器用百度账号登录并确认授权页面会给你一串授权码。把授权码粘回终端回车即可。授权成功后凭证会保存在~/.bypy/目录下后续所有命令都不用再授权。用bypy info可以查看当前账号的容量和已用空间bypy info这个命令会输出总容量、已使用空间以及当前的操作目录。看到Remote Dir: /apps/bypy就说明一切正常。有几个细节值得展开说。授权码有效期只有 10 分钟超时就得重来所以别慢慢悠悠复制。每台服务器只需要授权一次凭证文件可以整个复制到同账号的其他机器上省去重复授权但这个文件等于一把钥匙复制的时候注意文件权限chmod 600 ~/.bypy/* ls -la ~/.bypy/如果授权突然失效最常见的原因是长时间不用导致 refresh token 过期。解决办法是把~/.bypy下与授权相关的 json 文件删掉重新走一遍流程不要试图手动编辑 token 文件改坏了更难排查。3.2 目录和文件的基本操作bypy 的命令设计基本是照着 Unix 习惯来的学过 Linux 常用命令的人上手很快# 看远端当前目录有什么 bypy list # 看远端指定目录 bypy list /apps/bypy/backup # 建目录注意要写完整路径 bypy mkdir /apps/bypy/backup/2024 # 上传单个文件 bypy upload ./access.log.gz /apps/bypy/backup/2024/access.log.gz # 下载单个文件到当前目录 bypy downfile /apps/bypy/backup/2024/access.log.gz # 下载整个目录到本地指定位置 bypy downdir /apps/bypy/backup/2024 ./restored # 删除远端文件或目录 bypy delete /apps/bypy/backup/2024/access.log.gz这里有个容易踩的点upload的第二个参数如果是目录行为会不一样。写/apps/bypy/backup/2024/带斜杠它大概率会把文件丢进这个目录里不带斜杠又被当成文件名可能直接把目标覆盖掉。我现在的习惯是永远写完整的文件路径不给自己留歧义。还有一个坑是关于已存在文件的。bypy 上传前会先比对文件内容哈希如果远端已经有一模一样的文件它会跳过这在做增量备份时是好特性但如果你确实想覆盖就得先删再传或者用后面要讲的--no-resume之类的参数。我第一次做日志备份时上传了同一份文件两次第二次看到skipped还以为是传失败了白折腾半天。3.3 目录同步备份场景的主力命令真正让脚本好写的是这两个命令# 本地 - 远端只上传本地新增或变化的文件 bypy syncup /data/backup /apps/bypy/server-backup # 远端 - 本地 bypy syncdown /apps/bypy/server-backup /data/restoresyncup的语义是让远端和本地保持一致它会比较两端文件的大小和哈希只传有差异的部分。对于每天新增几个日志文件的备份场景这个命令的效率远高于每次全量上传。但要特别注意同步类命令在某些实现下会删除远端多出来的文件。这既是特性也是风险。我的做法是备份脚本里永远用syncup从本地推到远端绝不反向用syncdown去覆盖本地生产数据。另外第一次跑同步之前先用bypy compare干跑一次看看它会做什么bypy compare /data/backup /apps/bypy/server-backup这个命令只列差异不实际传输确认无误再真正执行能省掉很多手抖事故。3.4 把命令塞进定时任务备份脚本的核心就三行但外围要包一层错误处理和日志#!/bin/bash # /data/scripts/netdisk_backup.sh set -u export PATH/usr/local/bin:/usr/bin:/bin source /root/venv/netdisk/bin/activate LOG/data/logs/netdisk_backup.log REMOTE/apps/bypy/server-backup LOCAL/data/backup echo $(date %F %T) start $LOG bypy syncup $LOCAL $REMOTE $LOG 21 RET$? if [ $RET -ne 0 ]; then echo $(date %F %T) FAILED, exit$RET $LOG exit $RET fi echo $(date %F %T) done $LOG然后在 crontab 里加一行# 每天凌晨 4 点执行 0 4 * * * /bin/bash /data/scripts/netdisk_backup.sh这里有几个我踩过的坑必须说。第一cron 的环境变量极其贫瘠PATH 通常只有/usr/bin:/bin所以脚本开头必须自己 export PATH并且用绝对路径调用命令。第二cron 不会激活虚拟环境所以要么在脚本里 source要么直接用~/venv/netdisk/bin/bypy全路径。第三cron 的邮件输出默认会往系统邮箱塞不如自己重定向到日志文件排查起来方便。我第一次配这个任务时手动执行脚本一切正常一放进 cron 就报command not found折腾了半小时才反应过来是 PATH 的问题。这个坑几乎是每个人的必经之路。4. 关键参数与性能调优4.1 并发数、分片大小和重试次数怎么定bypy 的大文件传输涉及几个可调参数默认值能用但调对了能明显改善体验。以下是我在两台不同配置的服务器上实测出来的经验值参数默认建议值说明--processes12 到 4并发上传进程数。1核1G的小机器别超过 2否则内存吃紧--chunksize自动4M 到 16M分片大小。大文件调大能减少请求次数--retry58 到 10网络抖动时的重试次数服务器出口不稳就调高--timeout60120单次请求超时跨境或弱网环境调大用法示例bypy upload --processes 3 --chunksize 8M ./bigfile.tar.gz /apps/bypy/data/bigfile.tar.gz为什么并发不是越高越好因为服务端对同一账号有整体限流你把进程数拉到 10很可能不是变快而是一堆请求互相挤占配额最后集体超时。我在一台 2 核 4G 的机器上试过 1、2、4、8 四个档位2 和 4 的差距基本在误差范围内8 反而更慢还出现过部分分片失败。结论就是并发数控制在 4 以内先保证成功率再谈速度。分片大小也是有讲究的。分片太小会产生海量请求触发频率限制分片太大则单次失败后重传成本高。8M 到 16M 是我比较推荐的区间兼顾了重传代价和请求数量。4.2 大文件上传的断点续传逻辑bypy 在上传大文件时会先在远端创建一个占位文件然后逐片上传全部完成后做一次合并。如果中途断了下次执行同样的上传命令时它会检查远端已存在的分片并跳过已上传部分。这个机制意味着别在传输失败后急着删远端文件重来。先看看远端那个部分文件是不是还在在的话重新执行同一条命令多半能续上。只有反复失败、或者远端状态混乱时才需要清理后重来。如果确实需要强制重新上传可以加--no-resumebypy upload --no-resume ./bigfile.tar.gz /apps/bypy/data/bigfile.tar.gz另外单个文件特别大的时候比如超过 10G我更倾向于先本地切分再传# 切成 2G 一块 split -b 2G -d bigfile.tar.gz bigfile.part. # 上传所有分片 bypy upload ./bigfile.part.00 /apps/bypy/data/这样做的好处是任何一个分片失败只需要重传那 2G而不是整个文件。合并的时候在远端按顺序拼回去就行。这个思路在处理客户丢过来的超大日志包时特别管用。4.3 API 限流的表现和应对服务端的接口调用是有频率上限的脚本跑得太猛会撞上。常见的表现有几种返回码里带31064说明请求过于频繁。目录列表突然返回空但实际上远端有文件。上传进度卡在某个百分比不动最后超时。应对方式从简单到复杂有这么几层第一层在批量操作之间加 sleep。比如遍历一个目录下的几十个文件时每处理完一个 sleep 1 秒for f in $(ls /data/backup/*.gz); do bypy upload $f /apps/bypy/server-backup/ /data/logs/upload.log 21 sleep 1 done第二层减少无谓的 list 调用。每次bypy list都是一次请求所以脚本里不要把 list 结果在循环里反复获取拿到一次存到变量里复用。第三层给重试加上退避。简单的固定间隔重试在限流场景下效果一般指数退避更合适retry0 max_retry5 while [ $retry -lt $max_retry ]; do if bypy upload $FILE $REMOTE; then break fi retry$((retry1)) sleep_sec$((retry * retry * 5)) echo retry $retry after ${sleep_sec}s sleep $sleep_sec done这段逻辑的意思是第 1 次失败等 5 秒第 2 次等 20 秒第 3 次等 45 秒逐级拉开间隔。实测下来大部分限流导致的失败都能在前三次重试里恢复。5. 常见问题与排查技巧实录5.1 授权与凭证相关的问题问题跑任何命令都提示需要重新授权。先看~/.bypy/下的凭证文件在不在、权限对不对。有时候是因为用了 sudo 执行凭证被写到了 root 的家目录下而普通用户执行时读不到。解决方式就是统一执行身份别一会儿 sudo 一会儿不 sudo。问题授权链接打不开或者报错。检查服务器时间是否准确、系统根证书是否完整。时间偏差和证书缺失是两大隐形杀手。可以用curl -I https://openapi.baidu.com快速验证一下 HTTPS 通不通。问题凭证文件要共享给多台机器怎么办。直接把~/.bypy/整个目录打包传到目标机器相同路径下并把权限设为 600。但要注意这只适合你完全掌控的机器不要往共享服务器上放。5.2 传输类问题的速查表现象可能原因排查动作解决方式上传后网页端找不到文件默认目录在/apps/bypy在网页端查看我的应用数据直接访问/apps/目录大文件卡在某个百分比分片失败或网络中断查看日志里的错误码重新执行同命令续传或调小分片中文文件名变成问号系统 locale 是 C 或 POSIXlocale看 LANG 变量设置LANGen_US.UTF-8或zh_CN.UTF-8手动能跑cron 报错环境变量缺失看 cron 日志脚本里 export PATH用绝对路径下载速度很慢带宽策略限制对比网页端速度压缩后传、错峰执行、只传增量目录列表返回空触发了限流隔几分钟再试降低调用频率加 sleep权限被拒远端目录不存在bypy list确认路径先bypy mkdir建目录5.3 中文文件名乱码的彻底解决这个问题我遇到过两次表现是上传的中文文件名在网页端看是乱码或者在服务器bypy list时显示成问号。根因是系统 locale 没配好。先看现状locale如果输出里LANG是空的或者显示POSIX、C那基本就是它了。修复步骤sudo apt install -y locales sudo locale-gen en_US.UTF-8 sudo update-locale LANGen_US.UTF-8改完之后重新登录一次locale应该能看到LANGen_US.UTF-8。如果还是不行检查/etc/default/locale文件内容并确认LC_ALL没有被别的地方覆盖成C。注意修改 locale 会影响系统里所有依赖字符编码的程序不只是这个工具。改之前想清楚改完之后最好重启一下相关服务。5.4 几个只有踩过才知道的细节细节一不要在同一条命令里既上传又删远端文件。有些同步命令在传输完成后会清理远端多余文件如果传输过程中断清理逻辑可能仍然执行了导致远端数据被删但新数据没传上去。稳妥的顺序是先传完、验证无误、再单独删。细节二验证上传结果不要只看退出码。退出码为 0 只能说明命令执行完了不代表文件完整。重要的备份我还会再做一次大小比对LOCAL_SIZE$(stat -c %s $LOCAL_FILE) REMOTE_INFO$(bypy list $REMOTE_DIR | grep $(basename $LOCAL_FILE)) echo local$LOCAL_SIZE remote$REMOTE_INFO细节三给脚本加锁避免任务重叠。如果一次备份跑了 3 小时而 cron 每小时触发一次你会同时有多个进程在传同一批文件互相打架。用 flock 加个文件锁最省事exec 9/var/lock/netdisk_backup.lock flock -n 9 || { echo another instance is running; exit 1; }这四行放在脚本开头就能保证同一时刻只有一个实例在跑。6. 生产环境落地的几点经验6.1 备份策略增量为主全量为辅我在实际使用中发现把全量上传当成常规操作是行不通的。几百 G 的数据每天全传一遍既浪费时间又容易触发限流。合理的做法是分层每天跑增量只传当天新增的文件用syncup自动跳过已存在的。每周做一次全量校验用compare干跑一遍看看两端差异是否符合预期。每月做一次抽样恢复演练从网盘下载几个文件到临时目录确认能正常解压打开。这个抽样恢复演练是我强烈建议加上的。备份最大的谎言就是我以为备份成功了。只要没实际恢复过一次就不能算备份可用。我见过太多团队日志存了半年真要用的时候发现压缩包全是 0 字节。6.2 账号和权限的边界服务器上的自动化任务用的账号最好和日常使用的账号分开。原因有两个一是避免误操作把个人文件搞乱二是权限边界清晰出了问题好追溯。凭证文件的权限一定要收紧chmod 700 ~/.bypy chmod 600 ~/.bypy/*如果这台服务器是多用户共享的那微软的凭证就不能放在公共家目录下。可以考虑放到一个只有特定用户可读的目录通过环境变量或配置指定路径。另外不要在脚本里明文写任何令牌或者凭证。所有工具都应该走一次授权、本地存凭证的流程脚本只调用命令不接触密钥。6.3 监控让失败能被看见命令行任务最大的风险是静默失败。任务在凌晨三点挂了没人知道等你一个月后发现备份全断了。我的做法是给脚本加一个简单的健康检查。每次成功执行后往一个本地文件里写时间戳再配一个独立的检查脚本如果发现最近一次成功时间超过 26 小时就通过企业微信机器人或者邮件发告警#!/bin/bash # /data/scripts/check_backup.sh STAMP/data/logs/last_success.stamp if [ ! -f $STAMP ]; then echo no stamp found; exit 1 fi LAST$(cat $STAMP) NOW$(date %s) DIFF$(( (NOW - LAST) / 3600 )) if [ $DIFF -gt 26 ]; then echo backup overdue: ${DIFF}h # 这里接你的告警通道 fi对应地备份脚本在成功分支里写一下时间戳date %s /data/logs/last_success.stamp这套东西加起来不到二十行但能救命。6.4 关于传输效率说几句实在话非会员状态下下载带宽受到限制这是服务方的产品策略不是工具能绕过去的。我见过太多人在这上面浪费时间研究各种奇技淫巧最后发现还不如老老实实把文件压小。真正有效的优化就那么几条上传前用gzip -9或者zstd -19把文本类文件压到极限只传增量别重复传把并发控制在合理范围别把限流触发出来避开业务高峰执行大文件分片提高重传效率。这套组合下来一台普通云服务器每天同步几个 G 的日志是没问题的。如果业务量真的很大那就该考虑的是换更合适的方案比如用对象存储或者专业的备份服务而不是在网盘上硬扛。工具是解决特定问题的不是万能的。7. 最后几句实操体会这套方案我在两台云服务器上跑了两年多中间换过一次机器、重装过一次系统凭证目录直接打包迁移几乎没出过岔子。最大的体会是命令行工具的价值不在于能传文件而在于能被自动化。一旦它进了 crontab你就得按工程化的标准对待它——加锁、加日志、加重试、加告警把它当成一个正式的服务来维护而不是一个随手敲的命令。另外分享一个小技巧如果你需要在多台机器上用同一个账号可以把授权后的~/.bypy目录做成一个加密压缩包需要的时候解压到目标机器的对应位置权限设成 600用完就删。这比每台机器都走一遍授权流程省事也比明文散落凭证安全。再往后扩展如果你手上不只有百度网盘还有对象存储或者其他网盘可以考虑把同步脚本抽象成一个通用的 shell 函数前端参数化存储类型后端根据类型调用不同工具。这个改造我做过一次大概花了半天时间之后再加新存储后端就是十几行的事。到那一步你手里的就不是一个上传脚本而是一套小型的文件分发系统了。
返回列表