Preface {#preface}
前两天不小心执行了rm -rf ~
,OMG...
安装 git {#安装-git}
sudo apt install git
git config --global user.name 'Git用户名'
git config --global user.email "Git邮箱"
当然,在 Ubuntu 系统上一般都预先安装了。
新建 Git 仓库 {#新建-git-仓库}
在gitee
或Github
上新建仓库,是不是空仓库都行,专门用来储存备份的数据。
需要将本地的 ssh 公钥文件配置到对应的,Git 仓库服务商上。没有公钥文件通过ssh-keygen -t rsa -b 4096
生成一个,然后拷贝~/.ssh/id_rsa.pub
文件中的内容到 Git 仓库服务商上即可。
注意:由于一般的 Git 仓库服务商都会限制仓库的大小,所以不适合备份太大的文件。
新建备份脚本 {#新建备份脚本}
在任意目录新建备份脚本backup.sh
,要保证脚本对脚本所在的目录有写权限。
#!/bin/bash
# 定义变量,储存要备份的路径和对应的Git仓库地址
# 仓库地址可以多个或一个,多个的话要和 备份的路径 一一对应
backup_paths=(
"/home/ubuntu/backupdir1"
"/home/ubuntu/backupdir2"
)
git_repos=(
"git@xxxx.com:user/backup1.git"
"git@xxxx.com:user/backup2.git"
)
# 备份开始前的操作。
handle_before_backup() {
# 比如可以用来停止 docker 容器,mysql 等
# : 表示占位符,什么都不做,实际添加内容时你可以删掉它
:
}
# 自定义处理打包方式,函数中当前所在路径是对应上传备份的 git 本地仓库中,
# 只需将你要备份的文件放到当前目录即可,可以是 tar,mysqldump 等
handle_backup() {
# 备份路径 /home/xxx/backupdir
local backup_path=$1
# 备份目录名 backupdir
local backup_dir=$2
# 备份仓库地址 git@xxx.com:user/backup.git
local git_repo=$3
# 仓库名称 backup
local repo_name=$4
# 打包压缩
tar czf "$backup_dir.tar.gz" -C "$backup_path" .
}
# 备份完成后的操作。
handle_after_backup() {
# 比如可以用来启动 docker 容器,清除文件等。
# : 表示占位符,什么都不做,实际添加内容时你可以删掉它
:
}
# 在这之后的脚本内容就不需要更改了
# 存放备份地址的数组和仓库数组数量不一致,且仓库数组数量不唯一退出运行
if [ "${#git_repos[@]}" -ne 1 ] && [ "${#backup_paths[@]}" -ne "${#git_repos[@]}" ]; then
echo "数组数量错误,退出运行!"
exit
fi
# 获取脚本所在路径
script_path=$(readlink -f "$0")
backup_store_dir="${script_path}_store_dir"
# 使用条件判断备份文件存放目录是否存在
if [ ! -d "$backup_store_dir" ]; then
mkdir "$backup_store_dir"
# 检查 mkdir 命令的退出状态码
if [ ! $? -eq 0 ]; then
exit
fi
fi
# 备份并上传函数
backup_and_upload() {
local backup_path=$1
local git_repo=$2
echo -e "\n------------------ 开始备份 ${backup_path} ------------------\n"
# 进入备份
cd "$backup_store_dir"
# 获取目录名
local backup_dir=$(basename "$backup_path")
# 使用git命令获取仓库名称
local repo_name=$(basename "$git_repo" .git)
# 判断仓库是否不存在
if [ ! -d "$repo_name" ]; then
git clone "$git_repo"
# 检查 git clone 命令的退出状态码
if [ ! $? -eq 0 ]; then
# 克隆失败,手动初始化
mkdir "$repo_name"
cd "$repo_name"
git init
git remote add origin "$git_repo"
cd ..
fi
fi
# 目录不存在则退出函数
if [ ! -d "$repo_name" ]; then
exit
else
cd "$repo_name"
fi
# 拉取
git pull origin master
# 自定义处理打包方式
handle_backup "${backup_path}" "${backup_dir}" "${git_repo}" "${repo_name}"
# # 暂存、提交、推送
git add .
git commit -m $(date "+%Y-%m-%d~%H:%M:%S_${backup_dir}_数据备份")
git push -u origin master
}
# 调用备份开始前操作
handle_before_backup
# 循环读取备份路径对应的Git仓库地址,并执行备份并上传函数
for ((i=0; i<${#backup_paths[@]}; i++)); do
if [ "${#git_repos[@]}" -eq 1 ]; then
backup_and_upload "${backup_paths[i]}" "${git_repos[0]}"
else
backup_and_upload "${backup_paths[i]}" "${git_repos[i]}"
fi
done
# 调用备份完成后操作
handle_after_backup
修改脚本中的backup_paths
变量为你需要备份的文件夹或文件路径。
修改脚本中的git_repos
变量为你要备份到的仓库地址,需要和上面的backup_paths
一一对应,或者只设置一个,这样所有的备份文件都会上传到这个仓库中。如果只设置一个仓库要注意生成的备份文件名称不要重复,否则后面的备份文件会覆盖掉前面的备份文件。
修改handle_backup
函数内容,选择要备份的形式。比方说一些静态文件可用tar
命令打包,而数据库文件则不能直接用tar
打包,这样可能会造成数据错乱的现象,因为tar
是以递归的形式一个一个打包的,这种情况可以在handle_backup
函数中使用mysqldump
工具生成备份文件,或者在handle_backup
函数中先停止mysql
运行,然后执行tar
命令,等打包成功后再启动mysql
服务。
最后为脚本赋予可执行权限chmod +x backup.sh
设置定时任务 {#设置定时任务}
一般最好用root
账号来执行定时任务,以免发生权限不足的问题。如果确保没问题可忽略。
sudo su
crontab -e
设置每天凌晨 4 点执行一次,注意脚本路径要写绝对路径。
00 04 * * * /xxx/xxx/backup.sh
提示 {#提示}
github 和 gitee 个人免费版的仓库单文件大小都有限制,为 100MB,对于这种情况可以使用split
和cat
命令。
split
和 cat
是在 Unix/Linux 系统中常用的命令,它们分别用于拆分文件和合并文件的操作。
split
命令用于将一个大文件拆分成若干个较小的文件。其基本语法如下:
split [选项] 文件 [前缀]
- 选项:可以指定一些参数,如文件大小、行数等。常见的选项有
-b
(按字节拆分)、-l
(按行数拆分)等。 - 文件:需要拆分的大文件。
- 前缀:生成的小文件的前缀名。
示例:
split -b 10M docker-data.tar.gz backup
这个例子将 docker-data.tar.gz
按照 10MB 的大小拆分成多个文件,文件名以 backup
作为前缀。
cat
命令用于连接文件内容并打印到标准输出,也可以用于创建新文件。其基本语法如下:
cat [选项] [文件]
- 选项:可以指定一些参数,如
-n
(显示行号)、-b
(非空行显示行号)等。 - 文件:要连接的文件列表。
示例:
cat backup* > docker-data.tar.gz
这个例子将以 backup
开头文件的内容连接,并将结果输出到 docker-data.tar.gz
文件中。
所以通过此方法就可以将大文件分成多个小文件上传,等需要恢复备份时用cat
将分片合成一个即可。
还需要注意的点是仓库的总容量也是有上限的,因此要备份的文件是中大型文件需要定时清空或新建一个仓库。
参考资料 {#参考资料}
- Liunx 定时备份博客数据Git (dhjdd.cn)
- ChatGPT 3.5