我用一个简单的 bash 脚本和 cron 自动化了 Linux 备份(比图形界面更好)
摘要
- 编写一个 Bash 脚本来控制备份的内容、位置和运行时间。
- 使用 cron 安排可执行文件 backup.sh,并在运行后查看日志和目标位置。
- 测试脚本,使用绝对路径以避免 cron 和运行时的错误,并使用注释进行文档说明。
Déjà Dup 等工具提供了一种简单而出色的图形方式来自动执行 Linux 备份。然而,创建备份脚本是一种更高级的自动化备份 DIY 方法。它使您可以更好地控制备份内容、数据存储位置以及备份任务的频率。这也是学习基本脚本编写的有趣介绍。以下是我如何创建一个简单的备份脚本并使用 cron 自动执行备份任务。
创建一个简单的备份脚本并实现自动化
只要你编辑并更新脚本中的绝对路径,你的备份位置可以是本地文件夹、新的磁盘分区或外部驱动器。
选择备份目标
计划是创建一个精简的备份脚本,但我也想保留一些关键的 Linux 目录副本,以防我需要恢复系统。这个项目的备份位置是一块 128 GB 的 USB 闪存驱动器。
准备备份位置
无论你的备份位置是USB闪存驱动器、外部硬盘还是新分区,都要注意绝对目录路径和挂载点;一旦我们开始编写脚本,你将需要用到它们。
此备份脚本使用 rsync,rsync 通常在大多数发行版中已预装。请确认您的 rsync 版本,如果未安装,请使用包管理器进行安装。
我通过在挂载的 USB 闪存驱动器上创建一个名为“Backup”的新目录来启动项目。你可以通过图形界面在备份位置导航,然后使用快捷键 Ctrl+SHIFT+N 来创建这个文件夹。我选择使用终端,并使用了 lsblk、cd 和 mkdir 命令。
lsblk
cd “/media/htg/DATA BACKUP”
mkdir backup
rsync --version
sudo apt update -y && sudo apt install rsync决定备份内容并创建 backup.sh 脚本
为了系统恢复的目的,我选择备份一个包含整合个人文件和重要 Linux 目录(如 /home、/etc、/var、/usr/local、/root 和 /opt)的目录。大多数 Linux 终端文本编辑器都支持基本脚本。我使用 nano 在主目录中创建并保存了一个简单的 backup.sh bin bash 脚本。将以下脚本复制粘贴到你喜欢的终端文本编辑器中:
#!/bin/bash
# This bash script backs up Linux recovery directories and personal files
# Preserves ownership, permissions, timestamps, ACLs, and xattrs
set -euo pipefail
#------------This is the CONFIG script-----------
HOSTNAME="$(hostname)"
DATE="$(date +%F)"
BACKUP_ROOT="/media/htg/DATA BACKUP/Backup"
DEST_DIR="$BACKUP_ROOT/archives/${HOSTNAME}_${DATE}"
LOG_FILE="BACKUP_ROOT/logs/backup_${HOSTNAME}_${DATE}.log"
TMP_DIR="$BACKUP_ROOT/tmp"
#Don't forget to edit the BACKUP_ROOT, DEST_DIR, LOG_FILE and TMP_DIR paths
#Customize SOURCES=( to include the files and directories you want to back up
SOURCES=(
"/home"
"/etc"
"/var"
"/root"
"/opt"
"/usr/local"
"/home/htg/Backup"
)
EXCLUDES=(
"--exclude=/var/cache/"
"--exclude=/var/tmp/"
"--exclude=/var/lib/apt/lists/"
"--exclude=/home/*/.cache/"
"--exclude=/home/*/Downloads/"
"--exclude=/var/lib/docker/"
"--exclude=/var/lib/containers/"
)
# Add these flags for backup summary and progress:
# --info=progress2: Total progress line
# --info=name0: Hide individual filenames
# --stats: Final summary block
# --no-inc-recursive: Better progress accuracy
RSYNC_FLAGS=(-aAXH --numeric-ids --delete --human-readable --inplace --partial --info=progress2 --info=name0 --stats --no-inc-recursive)
# ---------- PREPARATION ----------
# Create destination folders on the flash drive
mkdir -p "$DEST_DIR" "$TMP_DIR" "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
# ---------- BACKUP ----------
echo "[$(date)] Starting backup to $DEST_DIR" | tee -a "$LOG_FILE"
for SRC in "${SOURCES[@]}"; do
echo "[$(date)] Backing up $SRC ..." | tee -a "$LOG_FILE"
# Run rsync and log output
rsync "${RSYNC_FLAGS[@]}" "${EXCLUDES[@]}" "$SRC" "$DEST_DIR" >>"$LOG_FILE" 2>&1
done
echo "[$(date)] Backup completed" | tee -a "$LOG_FILE"
# ---------- VERIFY ----------
echo "[$(date)] Listing destination sizes:" | tee -a "$LOG_FILE"
du -sh "$DEST_DIR"/* 2>/dev/null | tee -a "$LOG_FILE"
exit 0编辑脚本时,将 BACKUP_ROOT、DEST_DIR、LOG_FILE 和 TMP_DIR 替换为你的绝对路径,然后保存并退出;在 nano 中,使用 Ctrl+O+回车 和 Ctrl+X。下一步是使用 chmod 命令将脚本设为可执行,并使用 ls 命令确认执行权限(查看是否有 -x)。
nano ~/backup.sh
chmod +x ~/backup.sh
ls -l ~/backup.sh测试备份脚本并使用 cron 作业自动化
尽管所有备份策略最终都会失败,但测试备份系统和脚本可以减少灾难性数据丢失的可能性。它可以发现可能导致流程失败的错误,这是一个简单但至关重要的步骤,能够保障任何备份流程的完整性。在某些系统上,你可能需要使用 sudo 来测试运行脚本。
~/backup.sh
sudo ~/backup.sh如果脚本运行时出现错误,它将无法成功运行,但系统会打印出这些错误,你可以从中进行排查。如果一切正常,你会看到“正在启动备份”和“正在备份 /home..”的信息。如果你进入备份目标位置,应该能看到一些已备份的目录。
如果你正在将大量数据备份到外部硬盘,这个过程可能需要一段时间。只要没有收到错误信息,请耐心等待,即使看起来终端好像已经冻结。
在测试脚本并确认其可用后,我使用 cron 将其安排在晚上 8 点执行,使用 ls 命令确认已安排的备份任务,并使用 systemctl 命令检查 cron 服务的状态。
sudo crontab -e
0 20 * * * /usr/bin/bash /home/htg/backup.sh >> "/media/htg/DATA BACKUP/Backup/logs/cron_backup.log" 2>&1
sudo crontab -l
ls -l /home/htg/backup.sh
systemctl status cron此时,我已经成功创建并测试了我的备份脚本,并使用 cron 将其自动化。最后一步是确认备份过程,并在第二天晚上8点之后检查日志。
我通过艰难经历学到的三课
创建这个备份脚本是一次有趣且富有教育意义的经历。这个项目教会了我三个至今仍记忆犹新的课程。
始终测试备份脚本
我没有测试我的第一个备份脚本。你能猜到发生了什么吗?没错:当我运行测试备份时,脚本失败了。我花了一段时间才弄清楚原来我搞错了一个 shell 变量;我输入了 DATE+"$(date +%F)" 而不是 DATE="$(date +%F)",这导致第 10 行出现了“命令未找到”错误。
测试备份脚本可以发现可能导致执行错误的语法错误和权限错误。这也是一种良好的实践。
使用绝对路径
因为 cron 非常严格,错误可能导致 cron 任务失败,因此养成在脚本中使用完整的绝对目录和文件路径的习惯。这可以减少错误,简化备份,并有助于降低执行错误的发生。
评论你的脚本
对你的脚本进行注释就像是给未来的自己(以及其他人)留下便条,解释脚本中特定部分或章节的意图。在 Bash 脚本中,井号(#)是被广泛接受的注释方式。你可能已经注意到我的 Bash 脚本中有几个注释。
考虑一个例子:你需要在创建脚本六个月后进行修改。如果没有注释,错误编辑重要部分并破坏脚本的几率很高,因为脚本在你脑中已经不再新鲜。
这就是我如何用一个简单的 bash 脚本实现 Linux 备份自动化,以及我通过实践学到的三个教训。虽然编写脚本不是自动化备份的最简单方法,但它既有趣又有教育意义,尤其是如果你想学习基本的 bash 脚本编写。













