进阶课的前几篇,从最基础的命令一路讲到写脚本,讲的都是一个个独立的知识点。这一篇是"结业作业":把它们全部串起来,做一件几乎每个新手最终都会遇到的真实任务——给一份重要数据,写一个每天自动备份的脚本。这篇文章走完,你会发现前面学的东西,原来都是为了今天这一件事做准备。
假设你负责维护一个小型网站,数据存放在 /home/deploy/app/data 这个文件夹里。你希望做到:
- 只保留最近 7 天的备份,太旧的自动清理掉,不然备份会越堆越多,占满磁盘
- 每次备份,不管成功还是失败,都记一笔日志,方便以后查
这个需求看起来复杂,但拆开来看,全都是前面几篇讲过的东西。我们一步步搭出来。
一、先手动完成一次备份,搞清楚思路
在动手写脚本之前,先手动敲一遍完整流程,确认每一步都可行。
第一步:确认数据在哪,有多大(第一篇学的 pwd、ls)
cd /home/deploy/app/data
ls -la
第二步:把这份数据打包压缩
tar -czvf backup_test.tar.gz /home/deploy/app/data
tar 这个命令,系列里有专门一篇文章详细讲过每个参数的含义,这里先知道:这一行命令,能把整个文件夹压缩打包成一个文件。
第三步:确认打包出来的文件确实存在
ls -lh backup_test.tar.gz
手动走一遍,确认这几步都没问题,接下来就是把它们写进一个脚本里,让它能自动重复执行。
二、写出第一版脚本
#!/bin/bash
# 定义几个会用到的路径,方便以后统一修改
SOURCE_DIR="/home/deploy/app/data"
BACKUP_DIR="/home/deploy/backups"
TODAY=$(date +%F)
# 打包备份,文件名里带上今天的日期
tar -czvf $BACKUP_DIR/backup_$TODAY.tar.gz $SOURCE_DIR
几个新出现的地方解释一下:
**$(date +%F)**:这是把 date 命令的执行结果,直接放进变量里。%F 是日期格式,输出效果类似 2026-07-13。
为什么要把日期放进文件名? 如果不这么做,每次备份都叫同一个名字,新的备份会直接覆盖掉昨天的——那就完全失去"保留历史备份"的意义了。带上日期,每天的备份文件名都不一样,自然就都保留下来了。
先给这个脚本加上执行权限(系列前面权限那篇讲过):
chmod +x backup.sh
手动跑一次,试试看:
./backup.sh
去 $BACKUP_DIR 那个文件夹看看,应该能看到一个类似 backup_2026-07-13.tar.gz 的文件了。
三、给脚本加上"安全垫":备份文件夹不存在怎么办
如果 /home/deploy/backups 这个文件夹根本还不存在,上面那个脚本执行到打包那一步就会报错。给脚本加一个小小的保护:
#!/bin/bash
SOURCE_DIR="/home/deploy/app/data"
BACKUP_DIR="/home/deploy/backups"
TODAY=$(date +%F)
# 如果备份文件夹不存在,就先创建一个(这一篇新学的写法)
mkdir -p $BACKUP_DIR
tar -czvf $BACKUP_DIR/backup_$TODAY.tar.gz $SOURCE_DIR
mkdir -p 里的 -p 是一个很实用的参数:如果这个文件夹已经存在,就什么都不做,不会报错;如果不存在,就自动创建。 这样不管这个脚本是第一次运行还是第一百次运行,这一行都不会出问题。
四、加上日志:知道这个脚本每次到底跑得怎么样
系列讲日志那篇提到过:脚本运行得好不好,光靠"感觉"不靠谱,得有记录。
#!/bin/bash
SOURCE_DIR="/home/deploy/app/data"
BACKUP_DIR="/home/deploy/backups"
LOG_FILE="/home/deploy/backup.log"
TODAY=$(date +%F)
mkdir -p $BACKUP_DIR
echo"==== $(date) 开始备份 ====" >> $LOG_FILE
tar -czvf $BACKUP_DIR/backup_$TODAY.tar.gz $SOURCE_DIR
echo"==== $(date) 备份完成,文件:backup_$TODAY.tar.gz ====" >> $LOG_FILE
>> 这个符号,是把内容追加写入文件(系列讲管道重定向那篇详细讲过),确保每次运行的记录都保留下来,而不是每次都把之前的记录清空重写。
以后想知道这个脚本这段时间跑得怎么样,直接看这份日志就行:
tail -20 /home/deploy/backup.log
五、自动清理旧备份,不让它一直堆下去
系列讲磁盘那篇提到过,"东西一直堆积不清理"是磁盘写满的常见原因之一。备份文件不加控制地一直攒下去,迟早会撞上这个问题。
加上一行自动清理的逻辑:
#!/bin/bash
SOURCE_DIR="/home/deploy/app/data"
BACKUP_DIR="/home/deploy/backups"
LOG_FILE="/home/deploy/backup.log"
TODAY=$(date +%F)
mkdir -p $BACKUP_DIR
echo"==== $(date) 开始备份 ====" >> $LOG_FILE
tar -czvf $BACKUP_DIR/backup_$TODAY.tar.gz $SOURCE_DIR
echo"==== $(date) 备份完成 ====" >> $LOG_FILE
# 清理 7 天前的旧备份
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +7 -delete
echo"==== $(date) 已清理 7 天前的旧备份 ====" >> $LOG_FILE
这一行 find 命令,系列里有专门一篇文章详细讲过它的各种用法,这里的意思是:在备份文件夹里,找到所有名字以 backup_ 开头、超过 7 天没有更新过的文件,直接删除。
这样一来,备份文件夹里始终只保留最近 7 天的内容,不会无限膨胀下去。
六、让脚本每天自动运行,不用自己动手
脚本写好了,手动运行没问题,但每天凌晨都要自己爬起来手动运行一次,显然不现实。这时候需要让它"自动定期运行"——这正是系列里专门讲过的定时任务工具能做的事。
crontab -e
在打开的编辑界面里加一行:
0 2 * * * /home/deploy/backup.sh
这一行的意思是:每天凌晨 2 点,自动执行一次这个备份脚本。 具体的时间格式、以及定时任务里一些容易踩的坑(比如脚本里用到的命令路径问题),系列里有专门一篇文章详细讲过,这里不重复展开,只需要知道:写好的脚本,配合这一行配置,就能做到"每天自动、不用人管"。
七、完整的脚本,最终版本
把前面几步全部整合起来,这就是一个真正能在实际工作中使用的备份脚本:
#!/bin/bash
# ===== 配置区:以后想改路径、改保留天数,只需要改这里 =====
SOURCE_DIR="/home/deploy/app/data"
BACKUP_DIR="/home/deploy/backups"
LOG_FILE="/home/deploy/backup.log"
KEEP_DAYS=7
# ===== 正式执行 =====
TODAY=$(date +%F)
mkdir -p $BACKUP_DIR
echo"==== $(date) 开始备份 ====" >> $LOG_FILE
tar -czvf $BACKUP_DIR/backup_$TODAY.tar.gz $SOURCE_DIR
if [ $? -eq 0 ]
then
echo"备份成功:backup_$TODAY.tar.gz" >> $LOG_FILE
else
echo"备份失败!请检查具体原因" >> $LOG_FILE
fi
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +$KEEP_DAYS -delete
echo"==== $(date) 本次任务结束 ====" >> $LOG_FILE
echo"" >> $LOG_FILE
这里多了一个新东西:$?。
$? 是一个特殊变量,代表"上一条命令执行完之后,成功还是失败"。0 表示成功,非 0 表示出了问题。加上这个判断,脚本就能自己分辨这次备份到底是成功了还是失败了,分别记录不同的日志内容——这样以后打开日志一看,一眼就能知道哪天备份失败过。
八、结业检查:你现在已经具备的能力
回头看这一个脚本,用到了这个系列全部八篇文章的内容:
这就是这个系列真正想传达的东西:Linux 运维,从来不是背了多少条孤立的命令,而是能把这些命令,按照一个真实的需求,组织成一套可靠、可重复、能自动运行的解决方案。
写在最后
从第一篇的 pwd、ls,到今天这个能自动运行、自动清理、自动记录日志的备份脚本——这中间的距离,其实没有想象中那么远。每一步都是踩着前面学过的东西往上搭一层,没有一步是凭空跳跃的。
这个备份脚本,你完全可以拿去改一改路径,直接用在自己真实的服务器上——这也是学 Linux 最好的方式:不是看懂了多少篇文章,而是有没有真的写出过一个自己在用的东西。
你有没有已经在用类似的备份脚本?或者看完这篇,会想自己动手写一个解决什么问题?评论区聊聊。