文件
scripts/backup
2026-04-26 21:54:27 +08:00
..
2026-04-26 21:54:27 +08:00
2026-04-26 21:54:27 +08:00
2026-04-26 21:54:27 +08:00

backup.sh

把指定目录打包成 tar.gz,再上传到远端:当前支持 SMB / Sambarclone(覆盖 Google Drive / OneDrive / S3 / WebDAV 等所有 rclone 支持的远端)。同时支持 LinuxmacOS

SFTP 等其它方式已在脚本中预留入口(run_sftpSFTP_* 配置),目前未实现。

系统要求

  • bash 3.2+ / tar / date / split
  • sha256sumLinux 自带,属于 coreutilsshasummacOS 自带)
  • 上传 SMBsmbclientLinux 一般在 smbclientsamba-client 包中;macOS 推荐 brew install samba,没装会回退到 mount_smbfs
  • 上传 rclonerclone,且需提前用 rclone config 配好远端

安装依赖

系统 SMB rclone
Debian / Ubuntu apt install -y smbclient apt install -y rclone 或官方脚本
RHEL / Rocky / Alma dnf install -y samba-client dnf install -y rclone 或官方脚本
Arch pacman -S smbclient pacman -S rclone
macOS brew install samba(可选) brew install rclone
通用 curl https://rclone.org/install.sh | sudo bash

文件

backup/
├── backup.sh     # 主脚本
├── backup.conf   # 配置文件(与脚本同目录)
└── README.md

下载到本地

为避免后续脚本更新导致 bash <(curl ...) 形式的执行失效(参数变化、行为不兼容等),建议先下载到本地再执行:

# 创建目录并下载脚本与示例配置
mkdir -p ~/backup && cd ~/backup
curl -fsSL -o backup.sh   https://git.suhang.me/suhang/scripts/raw/branch/release/backup/backup.sh
curl -fsSL -o backup.conf https://git.suhang.me/suhang/scripts/raw/branch/release/backup/backup.conf
chmod +x backup.sh
chmod 600 backup.conf

# 编辑 backup.conf 后执行
bash backup.sh smb

也可改用 wget

wget -qO backup.sh   https://git.suhang.me/suhang/scripts/raw/branch/release/backup/backup.sh
wget -qO backup.conf https://git.suhang.me/suhang/scripts/raw/branch/release/backup/backup.conf

使用方式

bash backup.sh <method> [options]

method 取值:

方式 说明
smb 通过 SMB / Samba 上传
rclone 通过 rclone 上传到网盘 / 对象存储等任意 rclone 支持的远端
sftp 已预留入口,暂未实现

最常见的用法是先编辑同目录下的 backup.conf,然后执行:

bash backup.sh smb

配置文件 backup.conf

脚本默认读取 脚本所在目录 下的 backup.conf,可用 -C / --config 指定其它路径。

配置分三段:公共配置COMMON_*,所有方式都用)、SMB 段SFTP 段。备份方式由命令行第一个位置参数决定(smb / sftp),脚本只会读取该方式对应段的配置。backup.conf 里没有 METHOD 字段。

公共配置COMMON_*

字段 说明
COMMON_SOURCE_PATHS 要备份的源路径,多个用空格分隔,需引号包裹
COMMON_TMP_DIR 本地临时打包目录,默认 /tmp/backup
COMMON_ARCHIVE_PREFIX 归档/远端目录命名前缀,最终形如 prefix-YYYYmmdd-HHMMSS/
COMMON_CLEAN_LOCAL 上传后是否删除本地归档(true / false
COMMON_RETENTION_DAYS 远端保留天数,0 表示不清理;按目录整体清理
COMMON_SPLIT_SIZE 分卷大小(默认 1G500M / 100k 等),留空字符串不分卷

SMB 段

字段 说明
SMB_HOST SMB 服务器地址
SMB_SHARE 共享名
SMB_PATH 共享内的子目录(可选)
SMB_USER / SMB_PASSWORD 凭据
SMB_DOMAIN 域 / 工作组(可选)
SMB_VERSION SMB 协议版本,如 3.0(可选)

rclone 段

字段 说明
RCLONE_EXECUTABLE rclone 可执行文件路径(可选,留空则从 PATH 中查找)。装在非标准路径时填这里
RCLONE_REMOTE rclone 远端名(不带尾随冒号),例如 gdrive。需提前用 rclone config 配好
RCLONE_PATH 远端目标子路径,例如 vps-backup/web1
RCLONE_CONFIG 自定义 rclone.conf 路径(可选,留空则使用 ~/.config/rclone/rclone.conf
RCLONE_FLAGS 透传给 rclone 的额外参数(可选),常用:--bwlimit 10M --transfers 2 --tpslimit 4

网盘类远端Google Drive、OneDrive 等)建议加 --tpslimit 限制每秒事务数,避免触发风控;带宽紧张的服务器加 --bwlimit 限速。

SFTP 段(预留,暂未实现)

SFTP_HOST / SFTP_PORT / SFTP_USER / SFTP_PASSWORD / SFTP_KEY / SFTP_PATH

命令行参数

所有 backup.conf 中的字段均可通过命令行参数覆盖;命令行参数优先级最高。

通用

参数 对应配置
-C, --config FILE 指定配置文件路径
-s, --source "P1 P2" COMMON_SOURCE_PATHS
-t, --tmp-dir DIR COMMON_TMP_DIR
-p, --prefix NAME COMMON_ARCHIVE_PREFIX
--keep-local 等价于 COMMON_CLEAN_LOCAL=false
--retention DAYS COMMON_RETENTION_DAYS
--split-size SIZE COMMON_SPLIT_SIZE
--debug 打印详细调试日志(也可用 DEBUG=true 环境变量)
-h, --help 显示帮助

SMB

参数 对应配置
--smb-host HOST SMB_HOST
--smb-share NAME SMB_SHARE
--smb-path PATH SMB_PATH
--smb-user USER SMB_USER
--smb-password PASS SMB_PASSWORD
--smb-domain DOMAIN SMB_DOMAIN
--smb-version VER SMB_VERSION

rclone

参数 对应配置
--rclone-executable F RCLONE_EXECUTABLE
--rclone-remote NAME RCLONE_REMOTE
--rclone-path PATH RCLONE_PATH
--rclone-config FILE RCLONE_CONFIG
--rclone-flags STR RCLONE_FLAGS(整串透传,需引号包裹)

SFTP预留

--sftp-host --sftp-port --sftp-user --sftp-password --sftp-key --sftp-path

示例

完全依赖配置文件:

bash backup.sh smb

只用命令行参数(不依赖 backup.conf

bash backup.sh smb \
  -s "/etc /var/log /home/user/data" \
  --smb-host 192.168.1.10 \
  --smb-share backup \
  --smb-path servers/web1 \
  --smb-user backup \
  --smb-password 'P@ssw0rd' \
  --retention 30

混合使用(基础信息读 backup.conf,源路径临时覆盖):

bash backup.sh smb -s "/var/lib/mysql"

rclone 上传到 Google Driverclone config 配好名为 gdrive 的远端):

bash backup.sh rclone \
  --rclone-remote gdrive \
  --rclone-path vps-backup/web1 \
  --rclone-flags "--bwlimit 10M --transfers 2 --tpslimit 4" \
  --retention 30

完全依赖配置文件的 rclone 用法:

bash backup.sh rclone

rclone 远端的初始化

脚本本身不做交互式 OAuth,需要先在本机跑一次 rclone config

rclone config
# 选 n (new remote) -> 输入名字(如 gdrive-> 选存储类型 -> 跟着提示走
rclone listremotes      # 应能看到 "gdrive:"
rclone lsd gdrive:      # 验证可访问

之后把同样的远端名填到 backup.confRCLONE_REMOTE(不带冒号)。

定时任务

使用 >(单箭头)覆盖写入日志,避免日志文件无限增长——只保留最近一次执行的日志:

# 每天 03:10 跑一次
10 3 * * * /bin/bash /path/to/backup/backup.sh smb > /var/log/backup.log 2>&1

# 每天 03:17 跑一次
17 3 * * * /bin/bash /path/to/backup/backup.sh smb > /var/log/backup.log 2>&1

# 每两天 03:10 跑一次按月内的奇数日触发1、3、5……29、31
10 3 */2 * * /bin/bash /path/to/backup/backup.sh smb > /var/log/backup.log 2>&1

# 每 5 天 03:10 跑一次按月内日期号取模1、6、11、16、21、26、31
10 3 */5 * * /bin/bash /path/to/backup/backup.sh smb > /var/log/backup.log 2>&1

*/N 是按月内日期号取模,并不是严格意义的「每 N×24 小时」。月末跨月时会出现间隔被截短的情况(例如 */5 在 31 号触发后,次月 1 号又会触发);如对间隔严格要求,建议改用 systemd timer 的 OnUnitActiveSec=5d

如果有多条任务都写到同一个日志文件,请改用不同的日志路径(例如 /var/log/backup-0310.log/var/log/backup-0317.log),否则后一次会覆盖前一次。

macOS 可用 launchdcron(需要在「系统设置 → 隐私与安全性 → 完全磁盘访问权限」中授予 cron 权限以读取受保护目录)。

远端目录结构

每次备份在远端创建一个独立子目录SMB 与 rclone 行为一致),内含分卷文件与 SHA256 清单:

# SMB
//${SMB_HOST}/${SMB_SHARE}/${SMB_PATH}/
└── backup-20260426-031000/                         # 本次备份目录
    ├── backup-20260426-031000.tar.gz.0             # 分卷 0
    ├── backup-20260426-031000.tar.gz.1             # 分卷 1
    ├── backup-20260426-031000.tar.gz.2
    ├── ...
    └── backup-20260426-031000.sha256               # SHA256 清单(覆盖所有分卷)

# rclone
${RCLONE_REMOTE}:${RCLONE_PATH}/
└── backup-20260426-031000/
    ├── backup-20260426-031000.tar.gz.0
    ├── ...
    └── backup-20260426-031000.sha256

未启用分卷(COMMON_SPLIT_SIZE="")时目录里只有完整归档加清单:

backup-20260426-031000/
├── backup-20260426-031000.tar.gz
└── backup-20260426-031000.sha256

本地路径:

路径 说明
${COMMON_TMP_DIR}/${COMMON_ARCHIVE_PREFIX}-YYYYmmdd-HHMMSS.tar.gz 未分卷时的归档;分卷后会被删除
${COMMON_TMP_DIR}/${COMMON_ARCHIVE_PREFIX}-YYYYmmdd-HHMMSS.tar.gz.0 ... 分卷文件(默认上传后删除)
${COMMON_TMP_DIR}/${COMMON_ARCHIVE_PREFIX}-YYYYmmdd-HHMMSS.sha256 校验清单

分卷COMMON_SPLIT_SIZE

当单个归档过大、SMB 上传容易中途失败、或目标文件系统有单文件大小限制时启用分卷。默认 1G

# 配置文件
COMMON_SPLIT_SIZE="1G"

# 或命令行
bash backup.sh smb --split-size 500M

# 关闭分卷
bash backup.sh smb --split-size ''

注意:

  • 分卷需要本地临时空间约为「归档体积 × 2」先生成完整 .tar.gz,再 split。磁盘紧张时把 COMMON_TMP_DIR 指到大盘。
  • 远端清理(COMMON_RETENTION_DAYS)按 目录 清理:以 ${COMMON_ARCHIVE_PREFIX}-YYYYmmdd-HHMMSS 命名的目录里所有内容(含 sha256会一并删除。

校验与恢复

每次备份都会生成 <basename>.sha256 清单(标准 sha256sum 格式:<hash> <filename>),命名都用相对文件名,因此恢复时进入备份目录直接校验即可

进入备份目录:

cd /path/to/backup-20260426-031000/

校验完整性:

# Linux
sha256sum -c backup-20260426-031000.sha256

# macOS
shasum -a 256 -c backup-20260426-031000.sha256

合并分卷并解压(一步到位):

cat $(ls *.tar.gz.* | sort -V) | tar -xzf -

sort -V 是 version-sort自然数序,可正确排序 .tar.gz.0 .tar.gz.1 ... .tar.gz.10 .tar.gz.11。 直接 cat *.tar.gz.* 走的是 shell 字典序,会把 .10 排在 .2 前面,会损坏归档

如果只有一个文件(未分卷):

tar -xzf backup-20260426-031000.tar.gz

或者先合并成一个文件再解压:

cat $(ls *.tar.gz.* | sort -V) > backup-20260426-031000.tar.gz
tar -xzf backup-20260426-031000.tar.gz

注意事项

  • 命令行密码会出现在进程列表中,安全敏感场景请优先使用 backup.conf,并把权限收紧:chmod 600 backup.conf
  • macOS 上若未安装 smbclient,会回退到挂载方式(mount_smbfs),此时不支持 --retention 远端清理,仅完成上传。
  • 远端清理仅清理符合 ${COMMON_ARCHIVE_PREFIX}-YYYYmmdd-HHMMSS 命名规范的目录,避免误删其它内容。
  • rclone 上传完成后会自动用 rclone hashsum SHA256 拉取远端 hash 与本地 .sha256 清单逐项比对,校验失败会以非 0 状态码退出。少数远端(个别 WebDAV不支持 SHA256 hash,遇到这种情况脚本会报错退出,可改成手动下载后用 sha256sum -c 校验。
  • rclone 远端必须先在本机用 rclone config 配好;自定义 RCLONE_CONFIG 路径需保证脚本运行用户可读。