linux shell

关注公众号 jb51net

关闭
首页 > 脚本专栏 > linux shell > Linux Shell脚本文件备份

Linux Shell脚本实现文件备份功能

作者:Jinkxs

在现代运维与开发工作中,数据安全是生命线,无论是个人笔记、项目源码还是生产数据库,一旦丢失都可能造成不可逆的损失,Linux Shell 脚本作为系统管理的瑞士军刀,天然适合承担自动化备份任务,本文将带你从零构建一个功能完备、稳定可靠的备份脚本,需要的朋友可以参考下

引言

在现代运维与开发工作中,数据安全是生命线。无论是个人笔记、项目源码还是生产数据库,一旦丢失都可能造成不可逆的损失。Linux Shell 脚本作为系统管理的“瑞士军刀”,天然适合承担自动化备份任务。本文将带你从零构建一个功能完备、稳定可靠的备份脚本,并结合 Java 程序实现跨语言调度与监控,打造企业级备份解决方案。

为什么选择 Shell 做备份?

Shell 是 Linux/Unix 系统的原生脚本语言,具有以下无可替代的优势:

第一步:基础备份脚本搭建

我们从最简单的单文件备份开始,逐步迭代功能。

#!/bin/bash
# simple_backup.sh - 最简备份脚本 v0.1

SOURCE_FILE="/home/user/myproject/config.json"
BACKUP_DIR="/home/user/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="$BACKUP_DIR/config_$TIMESTAMP.json"

# 创建备份目录(如果不存在)
mkdir -p "$BACKUP_DIR"

# 执行复制
cp "$SOURCE_FILE" "$BACKUP_FILE"

echo "✅ 备份完成: $BACKUP_FILE"

这个脚本虽然简单,但已具备核心要素:

第二步:支持目录打包压缩

现实场景中,我们往往需要备份整个项目目录,这时候 tar + gzip 是黄金搭档。

#!/bin/bash
# dir_backup.sh - 目录压缩备份 v1.0
PROJECT_DIR="/home/user/myproject"
BACKUP_ROOT="/mnt/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
ARCHIVE_NAME="myproject_$TIMESTAMP.tar.gz"
BACKUP_PATH="$BACKUP_ROOT/$ARCHIVE_NAME"
mkdir -p "$BACKUP_ROOT"
# 使用 tar + gzip 打包压缩
tar -czf "$BACKUP_PATH" -C "$(dirname "$PROJECT_DIR")" "$(basename "$PROJECT_DIR")"
if [ $? -eq 0 ]; then
    echo "🎉 成功备份目录至: $BACKUP_PATH"
    ls -lh "$BACKUP_PATH"
else
    echo "❌ 备份失败!请检查源路径是否存在。"
    exit 1
fi

关键参数说明:

注意:-C 参数非常重要!它确保解压时不会覆盖系统根目录。

第三步:增加配置文件支持

硬编码路径不利于复用。我们引入 .ini 格式的配置文件,让脚本更具通用性。

config.ini

[backup]
source_dir = /home/user/myproject
backup_dir = /mnt/backups
max_backups = 5
compress = true

enhanced_backup.sh

#!/bin/bash
# enhanced_backup.sh - 支持配置文件的备份脚本 v2.0

CONFIG_FILE="./config.ini"

# 读取配置(简易版,不依赖外部工具)
get_config() {
    section=$1
    key=$2
    result=$(awk -F ' *= *' "/\[$section\]/,/\[.*\]/{if (\$1==\"$key\") print \$2}" "$CONFIG_FILE")
    echo "$result"
}

SOURCE_DIR=$(get_config "backup" "source_dir")
BACKUP_DIR=$(get_config "backup" "backup_dir")
MAX_BACKUPS=$(get_config "backup" "max_backups")
COMPRESS=$(get_config "backup" "compress")

TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BASENAME=$(basename "$SOURCE_DIR")

if [ "$COMPRESS" = "true" ]; then
    ARCHIVE_NAME="${BASENAME}_${TIMESTAMP}.tar.gz"
    BACKUP_PATH="$BACKUP_DIR/$ARCHIVE_NAME"
    mkdir -p "$BACKUP_DIR"
    tar -czf "$BACKUP_PATH" -C "$(dirname "$SOURCE_DIR")" "$BASENAME"
else
    BACKUP_PATH="$BACKUP_DIR/${BASENAME}_${TIMESTAMP}"
    mkdir -p "$BACKUP_PATH"
    cp -r "$SOURCE_DIR" "$BACKUP_PATH"
fi

# 清理旧备份(保留最新 N 个)
cd "$BACKUP_DIR" || exit 1
ls -t | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm -rf

echo "📦 备份成功: $BACKUP_PATH"
du -sh "$BACKUP_PATH"

第四步:增量备份与 rsync 同步

对于大文件或频繁变更的目录,全量备份效率低下。此时应使用 rsync 实现增量同步

#!/bin/bash
# incremental_backup.sh - 增量备份脚本 v3.0

SOURCE="/home/user/photos"
DEST="/backup/photos_$(date +%Y%m%d)"

# 使用 rsync 进行增量同步
rsync -av --delete "$SOURCE/" "$DEST/"

# -a: archive mode (保留权限、时间等)
# -v: verbose 输出详情
# --delete: 删除目标端多余文件(保持完全一致)

if [ $? -eq 0 ]; then
    echo "🔁 增量同步完成: $DEST"
else
    echo "⚠️ 同步过程中出现错误,请检查网络或权限。"
fi

第五步:定时任务集成(crontab)

再强大的脚本,不自动运行也是摆设。Linux 的 cron 是最佳搭档。

编辑定时任务:

crontab -e

添加如下行(每天凌晨 2 点执行):

0 2 * * * /path/to/your/backup_script.sh >> /var/log/backup.log 2>&1

你也可以设置更复杂的策略:

# 工作日每小时备份一次
0 * * * 1-5 /opt/scripts/hourly_backup.sh

# 周末凌晨全量备份
0 3 * * 6,0 /opt/scripts/full_backup.sh

查看当前用户的 cron 任务:

crontab -l

数据可视化:备份状态监控图表

为了直观展示备份历史和成功率,我们可以生成一个简单的统计报告。下面使用 mermaid 图表在 Markdown 中渲染备份趋势:

渲染错误: Mermaid 渲染失败: Parse error on line 5: ... section 成功备份 2024-06-01 :done, ----------------------^ Expecting 'EOF', 'SPACE', 'NL', 'weekday_monday', 'weekday_tuesday', 'weekday_wednesday', 'weekday_thursday', 'weekday_friday', 'weekday_saturday', 'weekday_sunday', 'weekend_friday', 'weekend_saturday', 'dateFormat', 'inclusiveEndDates', 'topAxis', 'axisFormat', 'tickInterval', 'excludes', 'includes', 'todayMarker', 'title', 'acc_title', 'acc_descr', 'acc_descr_multiline_value', 'section', 'taskTxt', 'click', got 'date'

此图可用于内部 Wiki 或运维看板,一目了然掌握系统健康度。

第六步:失败告警与邮件通知

无人值守的备份必须有告警机制。我们可以借助 mailsendmail 发送通知。

#!/bin/bash
# alert_backup.sh - 带邮件告警的备份脚本

EMAIL="admin@company.com"
SUBJECT="【备份告警】$(hostname) - $(date)"

backup_and_alert() {
    # 执行备份命令
    /path/to/real_backup.sh 2>&1
    local exit_code=$?

    if [ $exit_code -ne 0 ]; then
        echo "🚨 备份失败!退出码: $exit_code" | mail -s "$SUBJECT" "$EMAIL"
        echo "📧 告警邮件已发送至 $EMAIL"
    else
        echo "✅ 备份成功,无需告警。"
    fi

    return $exit_code
}

backup_and_alert

如果你没有配置本地邮件服务,也可以使用 curl 调用第三方 API(如 Mailgun、SendGrid):

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN/messages \
    -F from='Backup Bot <backup@yourdomain.com>' \
    -F to="$EMAIL" \
    -F subject="$SUBJECT" \
    -F text="备份任务执行失败,请立即检查!"

第七步:远程备份与云存储集成

除了本地磁盘,现代备份方案必须考虑异地容灾。我们可以将备份文件上传至云存储(如 AWS S3、阿里云 OSS)。

以 AWS CLI 为例:

#!/bin/bash
# cloud_backup.sh - 上传至 S3 的备份脚本

BUCKET_NAME="mycompany-backups"
LOCAL_BACKUP="/mnt/backups/latest.tar.gz"
S3_PATH="s3://$BUCKET_NAME/$(date +%Y/%m)/latest_$(date +%Y%m%d).tar.gz"

aws s3 cp "$LOCAL_BACKUP" "$S3_PATH" --storage-class STANDARD_IA

if [ $? -eq 0 ]; then
    echo "☁️ 文件已成功上传至 S3: $S3_PATH"
else
    echo "❌ 上传失败,请检查 AWS 凭证或网络连接。"
fi

第八步:单元测试与异常处理

工业级脚本必须包含错误处理和自检逻辑。

#!/bin/bash
# robust_backup.sh - 健壮型备份脚本 v4.0

set -euo pipefail  # 严格模式:遇到错误/未定义变量/管道失败时立即退出

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
}

die() {
    log "❌ ERROR: $*"
    exit 1
}

# 参数校验
[ -z "$SOURCE_DIR" ] && die "SOURCE_DIR 未设置"
[ ! -d "$SOURCE_DIR" ] && die "源目录不存在: $SOURCE_DIR"
[ -z "$BACKUP_DIR" ] && die "BACKUP_DIR 未设置"

# 磁盘空间检查
required_space=$(du -sb "$SOURCE_DIR" | cut -f1)
available_space=$(df -B1 "$BACKUP_DIR" | tail -1 | awk '{print $4}')

if [ "$available_space" -lt "$required_space" ]; then
    die "目标磁盘空间不足!需要: $required_space, 可用: $available_space"
fi

# 执行备份...
log "开始备份 $SOURCE_DIR → $BACKUP_DIR"
# ... 实际备份逻辑 ...

log "✅ 备份任务成功完成"

第九步:Java 调度器联动实战

虽然 Shell 强大,但在复杂业务系统中,我们常需通过 Java 应用触发或监控备份任务。下面是一个 Spring Boot 示例:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@Component
public class BackupScheduler {
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点
    public void triggerDailyBackup() {
        try {
            ProcessBuilder pb = new ProcessBuilder("/opt/scripts/daily_backup.sh");
            pb.redirectErrorStream(true); // 合并 stderr 和 stdout
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream())
            );
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println("[Backup Script]: " + line);
            }
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("✅ Java调度:备份任务成功完成");
            } else {
                System.err.println("❌ Java调度:备份脚本执行失败,退出码:" + exitCode);
                // 可在此处集成企业微信/钉钉告警
            }
        } catch (Exception e) {
            System.err.println("💥 Java调度异常:" + e.getMessage());
            e.printStackTrace();
        }
    }
}

Maven 依赖(如需异步或高级调度):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

第十步:备份日志分析与报表生成

我们可以编写一个 Java 工具类,定期分析备份日志,生成 HTML 报表。

import java.nio.file.*;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
public class BackupLogAnalyzer {
    public static void generateReport(String logPath, String outputPath) {
        try {
            List<String> lines = Files.readAllLines(Paths.get(logPath));
            Map<LocalDate, Long> successByDay = new TreeMap<>();
            Map<LocalDate, Long> failureByDay = new TreeMap<>();
            for (String line : lines) {
                if (line.contains("✅")) {
                    LocalDate date = extractDate(line);
                    successByDay.merge(date, 1L, Long::sum);
                } else if (line.contains("❌")) {
                    LocalDate date = extractDate(line);
                    failureByDay.merge(date, 1L, Long::sum);
                }
            }
            StringBuilder html = new StringBuilder();
            html.append("<html><head><title>备份日报表</title></head><body>");
            html.append("<h1>📊 近期备份统计</h1><table border='1'>");
            html.append("<tr><th>日期</th><th>成功次数</th><th>失败次数</th></tr>");
            for (LocalDate date : successByDay.keySet()) {
                long success = successByDay.getOrDefault(date, 0L);
                long failure = failureByDay.getOrDefault(date, 0L);
                html.append(String.format(
                    "<tr><td>%s</td><td>%d</td><td>%d</td></tr>",
                    date, success, failure
                ));
            }
            html.append("</table></body></html>");
            Files.write(Paths.get(outputPath), html.toString().getBytes());
            System.out.println("📈 报表已生成:" + outputPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static LocalDate extractDate(String line) {
        // 假设日志格式:[2024-06-01 02:00:00] ✅ 备份完成...
        int start = line.indexOf('[') + 1;
        int end = line.indexOf(' ', start);
        String dateStr = line.substring(start, end);
        return LocalDate.parse(dateStr);
    }
}

调用方式:

BackupLogAnalyzer.generateReport(
    "/var/log/backup.log",
    "/var/www/html/backup_report.html"
);

第十一步:多环境适配(开发/测试/生产)

企业环境中,同一套脚本需适应不同部署环境。我们可以通过环境变量或参数注入实现。

#!/bin/bash
# multi_env_backup.sh

ENV=${BACKUP_ENV:-development}  # 默认 development
CONFIG_FILE="config.$ENV.ini"

if [ ! -f "$CONFIG_FILE" ]; then
    echo "❌ 配置文件不存在: $CONFIG_FILE"
    exit 1
fi

# 加载对应环境配置
source "$CONFIG_FILE"

case "$ENV" in
    production)
        echo "🚀 生产环境备份启动..."
        MAX_BACKUPS=30
        ;;
    staging)
        echo "🧪 预发布环境备份启动..."
        MAX_BACKUPS=10
        ;;
    development)
        echo "💻 开发环境备份启动..."
        MAX_BACKUPS=5
        ;;
    *)
        echo "⚠️ 未知环境: $ENV"
        exit 1
        ;;
esac

# ... 执行备份逻辑 ...

对应的配置文件:

config.production.ini

source_dir=/opt/app/data
backup_dir=/mnt/nas/prod_backups
compress=true

config.development.ini

source_dir=/home/dev/project
backup_dir=/tmp/dev_backups
compress=false

第十二步:加密与安全性增强

敏感数据备份必须加密。我们可以使用 gpgopenssl

#!/bin/bash
# encrypted_backup.sh

PASSPHRASE="your-secret-passphrase"  # 生产环境应从密钥管理服务获取
BACKUP_FILE="/tmp/data_$(date +%Y%m%d).tar.gz"
ENCRYPTED_FILE="$BACKUP_FILE.enc"

# 1. 打包压缩
tar -czf "$BACKUP_FILE" /path/to/data

# 2. 使用 openssl 加密
openssl enc -aes-256-cbc -salt -in "$BACKUP_FILE" -out "$ENCRYPTED_FILE" -k "$PASSPHRASE"

# 3. 安全删除原始文件
shred -u "$BACKUP_FILE"

echo "🔐 备份文件已加密并保存为: $ENCRYPTED_FILE"

解密命令:

openssl enc -d -aes-256-cbc -in backup.tar.gz.enc -out backup.tar.gz -k "your-secret-passphrase"

生产建议:使用 HashiCorp Vault 或 AWS KMS 管理密钥,而非硬编码。

第十三步:Docker 环境下的备份策略

容器化时代,数据卷(Volume)的备份尤为重要。

#!/bin/bash
# docker_volume_backup.sh

CONTAINER_NAME="mysql_db"
VOLUME_NAME="db_data"
BACKUP_DIR="/backups/mysql"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")

# 1. 进入容器执行 mysqldump
docker exec "$CONTAINER_NAME" mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --all-databases > "$BACKUP_DIR/all_dbs_$TIMESTAMP.sql"

# 2. 压缩
gzip "$BACKUP_DIR/all_dbs_$TIMESTAMP.sql"

# 3. 备份整个 volume(可选)
docker run --rm \
    -v "$VOLUME_NAME:/volume" \
    -v "$BACKUP_DIR:/backup" \
    alpine tar -czf "/backup/volume_${TIMESTAMP}.tar.gz" -C /volume .

echo "🐳 Docker 数据卷备份完成"

第十四步:合规性与审计追踪

金融、医疗等行业需满足 GDPR、HIPAA 等法规,要求备份可审计。

我们在脚本中加入审计日志:

AUDIT_LOG="/var/log/backup_audit.log"

audit_log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S'),$USER,$(hostname),$1,$2" >> "$AUDIT_LOG"
}

# 在关键操作前后调用
audit_log "START" "/home/user/docs"
# ... 执行备份 ...
audit_log "SUCCESS" "/home/user/docs"

生成的审计日志示例:

2024-06-01 02:00:01,root,server01,START,/home/user/docs
2024-06-01 02:00:45,root,server01,SUCCESS,/home/user/docs
2024-06-02 02:00:02,root,server01,START,/home/user/docs
2024-06-02 02:00:51,root,server01,FAILED,/home/user/docs

第十五步:交互式备份工具(进阶)

为方便非技术人员使用,我们可以构建一个带菜单的交互式脚本:

#!/bin/bash
# interactive_backup.sh

show_menu() {
    clear
    echo "🖥️  文件备份管理系统 v1.0"
    echo "========================="
    echo "1) 备份文档目录"
    echo "2) 备份图片目录"
    echo "3) 查看备份历史"
    echo "4) 恢复最近备份"
    echo "5) 退出"
    echo
    read -p "请选择操作 (1-5): " choice
}

while true; do
    show_menu
    case $choice in
        1)
            ./backup_docs.sh
            read -p "按回车键返回主菜单..."
            ;;
        2)
            ./backup_photos.sh
            read -p "按回车键返回主菜单..."
            ;;
        3)
            ls -lt /backups/ | head -10
            read -p "按回车键返回主菜单..."
            ;;
        4)
            echo "正在恢复最近的文档备份..."
            # 恢复逻辑
            read -p "按回车键返回主菜单..."
            ;;
        5)
            echo "👋 感谢使用,再见!"
            break
            ;;
        *)
            echo "❌ 无效选择,请输入 1-5"
            sleep 2
            ;;
    esac
done

总结:构建企业级备份体系的 7 大原则

  1. 自动化 —— 无人值守,定时执行
  2. 可验证 —— 每次备份后校验完整性
  3. 可恢复 —— 定期演练恢复流程
  4. 异地多副本 —— 至少 3 副本,2 种介质,1 份异地
  5. 加密安全 —— 敏感数据必须加密存储
  6. 监控告警 —— 失败立即通知责任人
  7. 文档化 —— 操作手册、恢复步骤清晰可查

下一步:拥抱 DevOps 与 GitOps

现代备份不应孤立存在。将其纳入 CI/CD 流水线,配合基础设施即代码(IaC),才能实现真正的“韧性架构”。

例如,在 Terraform 中声明备份策略:

resource "aws_backup_plan" "daily" {
  name = "Daily-Backups"

  rule {
    rule_name         = "Daily-Rule"
    target_vault_name = aws_backup_vault.main.name
    schedule          = "cron(0 2 * * ? *)"

    lifecycle {
      delete_after = 30
    }
  }
}

结语

备份不是“有了就行”,而是“随时能用才叫备份”。通过本文的 Shell 脚本 + Java 联动方案,你可以构建出适应中小型企业需求的自动化备份系统。记住:最好的备份策略,是在灾难发生前就已经验证过恢复流程的策略。

现在就开始行动吧 —— 今天的一行脚本,可能是明天拯救项目的救命稻草。

以上就是Linux Shell脚本实现文件备份功能的详细内容,更多关于Linux Shell脚本文件备份的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文