Macos 定时备份文件夹到阿里云盘

2025-08-16 开发记录 24 1

通常自己非常重要的代码,需要备份,所以我利用rclone实现了一个每天早上5点准时备份文件夹到阿里云盘的脚本文件,远端保留最新的7份,会自动清理旧的备份文件,防止备份文件不断增多。

安装 rclone

1.终端命令执行安装命令

brew install zstd rclone

2.安装完成后,安装openlist(原alist),并且把阿里云盘挂载到你的openlist上,https://github.com/OpenListTeam/OpenList

3.配置openlist,在openlist上启用webdav功能

rclone config create alist webdav \
  url http://192.168.9.249:5244/dav \
  vendor other user admin pass '你的openlist密码'

4.验证阿里云盘是否能成功通讯

rclone lsd alist:

备份脚本

aliyun-backup.sh

#!/bin/bash
set -euo pipefail

# ===== 可改参数 =====
SRC="/Users/zony/Developer"
REMOTE="alist:/aliyun-backup/Developer"   # AList WebDAV 的目标目录
WORKDIR="/tmp/mcbak"                      # 本地临时打包目录
THREADS="0"                               # zstd 线程数;0=自动用满
LEVEL="${LEVEL:-5}"                       # 压缩等级:3~7 性价比最好;19 压得更小但慢

RCLONE="$(command -v rclone)"
ZSTD="$(command -v zstd)"
TAR="$(command -v tar)"

mkdir -p "$WORKDIR"

# 先确保远端目录存在——某些 WebDAV/后端不让 MKCOL 在根建,失败就提示你先在 UI 手建
if ! $RCLONE mkdir "$REMOTE" 2>/dev/null; then
  echo "[warn] 远端不允许自动创建目录:$REMOTE"
  echo "[hint] 去 AList 界面先手动建好 /aliyun-backup/Developer 再跑。"
fi

# 生成带时间戳文件名(按字典序 & 时间序一致)
TS="$(date +%Y%m%d-%H%M%S)"
ARCHIVE="developer-${TS}.tar.zst"
ARCHIVE_PATH="${WORKDIR}/${ARCHIVE}"

echo "[*] 打包 $SRC → $ARCHIVE_PATH  (zstd -T${THREADS} -${LEVEL})"
# 如需排除垃圾目录,给 tar 加 --exclude(示例已给)
$TAR \
  --exclude='.git' \
  --exclude='*/.git' \
  --exclude='node_modules' \
  --exclude='*/node_modules' \
  --exclude='vendor' \
  --exclude='*/vendor' \
  --exclude='build' \
  --exclude='*/build' \
  --exclude='dist' \
  --exclude='*/dist' \
  -C "$SRC" -cf - . \
| $ZSTD -T"$THREADS" -"$LEVEL" --long=31 -o "$ARCHIVE_PATH"

# 可选:生成校验
shasum -a 256 "$ARCHIVE_PATH" | awk '{print $1}' > "${ARCHIVE_PATH}.sha256" || true

echo "[*] 上传到远端 ${REMOTE}/${ARCHIVE}"
# WebDAV 走 AList,不用 Google Drive 的那些专有参数;加上防睡眠、重试、超时即可
caffeinate -dimsu "$RCLONE" copyto "$ARCHIVE_PATH" "${REMOTE}/${ARCHIVE}" \
  --transfers 1 --checkers 4 \
  --contimeout 30s --timeout 1h \
  --retries 10 --low-level-retries 20 --retries-sleep 10s \
  --progress --log-level INFO

# 同步校验(可选,不影响主流程)
caffeinate -dimsu "$RCLONE" copyto "${ARCHIVE_PATH}.sha256" "${REMOTE}/${ARCHIVE}.sha256" \
  --transfers 1 --checkers 4 --log-level INFO || true

echo "[*] 远端只保留最新 7 份,开始清理旧备份…"
# 兼容老版本 rclone:用 lSL 输出 + 本地 sort/awk 处理;过滤掉目录和 .sha256 校验文件
TO_DELETE=$("$RCLONE" lsl "$REMOTE" \
  | awk '$NF !~ /\/$/' \
  | grep -v '\.sha256$' \
  | sort -k2,2r -k3,3r \
  | awk '{print $NF}' \
  | tail -n +8)

if [ -n "$TO_DELETE" ]; then
  while IFS= read -r f; do
    [ -z "$f" ] && continue
    "$RCLONE" delete "${REMOTE}/${f}" && echo "[del] ${f}"
    # 删除对应的 .sha256 校验文件
    SHA_FILE="${f}.sha256"
    if "$RCLONE" delete "${REMOTE}/${SHA_FILE}" 2>/dev/null; then
      echo "[del] ${SHA_FILE}"
    fi
  done <<< "$TO_DELETE"
else
  echo "[*] 无需删除。"
fi

echo "[*] 删除本地临时包"
rm -f "$ARCHIVE_PATH" "${ARCHIVE_PATH}.sha256" 2>/dev/null || true

echo "[OK] 完成:${ARCHIVE}

定时执行

在您Mac电脑的这个目录下建立个文件:~/Library/LaunchAgents/com.zony.alist.devbackup.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.zony.alist.devbackup</string>

  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>/Users/zony/aliyun_backup.sh</string>
  </array>

  <!-- 每天 05:00 -->
  <key>StartCalendarInterval</key>
  <dict><key>Hour</key><integer>5</integer><key>Minute</key><integer>0</integer></dict>

  <!-- 给 rclone / zstd 准备 PATH -->
  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key>
    <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
  </dict>

  <!-- 调试期:加载即跑一遍 -->
  <key>RunAtLoad</key><true/>

  <key>StandardOutPath</key><string>/tmp/alist.devbackup.out</string>
  <key>StandardErrorPath</key><string>/tmp/alist.devbackup.err</string>
</dict></plist>

卸载定时任务

launchctl unload ~/Library/LaunchAgents/com.zony.alist.devbackup.plist 2>/dev/null || true

挂载定时任务

launchctl print gui/$(id -u)/com.zony.alist.devbackup | egrep 'state|pid|last exit'

查看日志

tail -n 200 /tmp/alist.devbackup.out /tmp/alist.devbackup.err
2025-08-18 08:19:56 backup