9.2 KiB
backup.sh
把指定目录打包成 tar.gz,再通过 SMB / Samba 上传到远端服务器。同时支持 Linux 与 macOS。
SFTP 等其它方式已在脚本中预留入口(
run_sftp、SFTP_*配置),目前未实现。
系统要求
- bash 3.2+ / tar / date / split
sha256sum(Linux 自带,属于 coreutils)或shasum(macOS 自带)- Linux:
smbclient(包含在smbclient或samba-client包中) - macOS:
smbclient(推荐,brew install samba),或退回到系统自带的mount_smbfs
安装依赖
| 系统 | 命令 |
|---|---|
| Debian / Ubuntu | apt install -y smbclient |
| RHEL / Rocky / Alma | dnf install -y samba-client |
| Arch | pacman -S smbclient |
| macOS | brew install samba(可选,无则使用 mount_smbfs) |
文件
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 上传 |
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 |
分卷大小(默认 1G;500M / 100k 等),留空字符串不分卷 |
SMB 段
| 字段 | 说明 |
|---|---|
SMB_HOST |
SMB 服务器地址 |
SMB_SHARE |
共享名 |
SMB_PATH |
共享内的子目录(可选) |
SMB_USER / SMB_PASSWORD |
凭据 |
SMB_DOMAIN |
域 / 工作组(可选) |
SMB_VERSION |
SMB 协议版本,如 3.0(可选) |
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 |
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"
定时任务
使用 >(单箭头)覆盖写入日志,避免日志文件无限增长——只保留最近一次执行的日志:
# 每天 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
*/2是按月内日期号取模,并不是严格意义的「每 48 小时」。在 31 天月份的月末会出现 31 → 次月 1 号连续两天都触发的情况;如对间隔严格要求,建议改用 systemd timer 的OnUnitActiveSec=2d。
如果有多条任务都写到同一个日志文件,请改用不同的日志路径(例如
/var/log/backup-0310.log、/var/log/backup-0317.log),否则后一次会覆盖前一次。
macOS 可用 launchd 或 cron(需要在「系统设置 → 隐私与安全性 → 完全磁盘访问权限」中授予 cron 权限以读取受保护目录)。
远端目录结构
每次备份在远端创建一个独立子目录,内含分卷文件与 SHA256 清单:
//${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 清单(覆盖所有分卷)
未启用分卷(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命名规范的目录,避免误删其它内容。