🏆 Day 7 of 7

综合实战项目

📖 预计时长:3 小时 🎯 难度:综合
将前6天学习的所有知识融会贯通,完成5个实际运维场景的完整项目脚本。这些脚本稍作修改即可在生产环境中使用。
系统健康巡检脚本 自动备份与轮转 Nginx 日志分析报告 服务监控告警 交互式运维菜单
🏅
综合实战说明今天的5个项目涵盖了运维日常最常用的场景。每个脚本都包含完整的错误处理、日志记录、参数处理,可以直接部署使用。建议边读边动手练习。
1

🔍 系统健康巡检脚本

检查 CPU、内存、磁盘、网络、关键服务,生成巡检报告

#!/usr/bin/env bash
# ============================================================
# 系统健康巡检脚本 health_check.sh
# 用法:./health_check.sh [--report] [--alert]
# ============================================================
set -euo pipefail

REPORT_FILE="/tmp/health_$(date +%Y%m%d_%H%M%S).txt"
CPU_WARN=80; MEM_WARN=85; DISK_WARN=90
ALERT=0; REPORT=0
STATUS="OK"

# 解析参数
for arg in "$@"; do
    case "$arg" in
        --report) REPORT=1 ;;
        --alert)  ALERT=1 ;;
    esac
done

# 彩色输出
ok()   { printf "\e[32m  ✓ %-30s %s\e[0m\n" "$1" "$2"; }
warn() { printf "\e[33m  ⚠ %-30s %s\e[0m\n" "$1" "$2"; STATUS="WARN"; }
fail() { printf "\e[31m  ✗ %-30s %s\e[0m\n" "$1" "$2"; STATUS="FAIL"; }

echo "===== 系统健康巡检 $(date '+%Y-%m-%d %H:%M:%S') ====="
echo "主机: $(hostname)  IP: $(hostname -I | awk '{print $1}')"
echo

# 1. CPU 使用率
echo "[CPU]"
cpu_idle=$(vmstat 1 2 | tail -1 | awk '{print $15}')
cpu_usage=$((100 - cpu_idle))
if (( cpu_usage >= CPU_WARN )); then
    warn "CPU 使用率" "${cpu_usage}% (阈值 ${CPU_WARN}%)"
else
    ok "CPU 使用率" "${cpu_usage}%"
fi

# 2. 内存使用率
echo "[内存]"
read total used <<< $(free -m | awk '/^Mem/{print $2, $3}')
mem_pct=$((used * 100 / total))
if (( mem_pct >= MEM_WARN )); then
    warn "内存使用率" "${mem_pct}% (${used}MB/${total}MB)"
else
    ok "内存使用率" "${mem_pct}% (${used}MB/${total}MB)"
fi

# 3. 磁盘使用率
echo "[磁盘]"
while IFS= read -r line; do
    usage=$(awk '{print $5}' <<< "$line" | tr -d '%')
    mount=$(awk '{print $6}' <<< "$line")
    if (( usage >= DISK_WARN )); then
        warn "磁盘 $mount" "${usage}%"
    else
        ok "磁盘 $mount" "${usage}%"
    fi
done < <(df -h | grep '^/dev')

# 4. 关键服务
echo "[服务]"
for svc in sshd nginx mysql firewalld; do
    if systemctl is-active "$svc" >/dev/null 2>&1; then
        ok "$svc" "running"
    else
        fail "$svc" "stopped!"
    fi
done

echo
echo "巡检结果:$STATUS"
bash
2

💾 自动备份与轮转脚本

增量/全量备份、日志轮转、自动清理旧备份

#!/usr/bin/env bash
# 自动备份脚本 backup.sh
# 用法: ./backup.sh [full|incr] [源目录] [备份根目录]
set -euo pipefail

MODE="${1:-full}"
SRC_DIR="${2:-/var/www/html}"
BACKUP_ROOT="${3:-/backup}"
KEEP_DAYS=30
DATE=$(date '+%Y%m%d_%H%M%S')
LOG="$BACKUP_ROOT/logs/backup_$(date '+%Y%m%d').log"

# 初始化
mkdir -p "$BACKUP_ROOT/full" "$BACKUP_ROOT/incr" "$BACKUP_ROOT/logs"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" | tee -a "$LOG"; }

log "===== 开始 $MODE 备份 ====="
log "源: $SRC_DIR"

case "$MODE" in
    full)
        DEST="$BACKUP_ROOT/full/backup_$DATE.tar.gz"
        tar -czf "$DEST" "$SRC_DIR"
        log "全量备份完成: $DEST ($(du -sh "$DEST" | cut -f1))"
        ;;
    incr)
        DEST="$BACKUP_ROOT/incr/incr_$DATE.tar.gz"
        # 只备份24小时内修改的文件
        tar -czf "$DEST" --newer-mtime="24 hours ago" "$SRC_DIR" 2>/dev/null || true
        log "增量备份完成: $DEST"
        ;;
    *)
        log "ERROR: 未知模式 '$MODE',请使用 full 或 incr"
        exit 1
        ;;
esac

# 清理旧备份
log "清理 $KEEP_DAYS 天前的备份..."
deleted=$(find "$BACKUP_ROOT" -name "*.tar.gz" -mtime +"$KEEP_DAYS" -print -delete | wc -l)
log "已清理 $deleted 个旧备份文件"

# 备份 MD5 校验
md5sum "$DEST" > "${DEST}.md5"
log "MD5: $(cat "${DEST}.md5")"
log "===== 备份完成 ====="
bash
3

📊 Nginx 访问日志分析报告

解析日志,生成可读性强的 HTML 报告

#!/usr/bin/env bash
# Nginx 日志分析 nginx_report.sh

LOG="${1:-/var/log/nginx/access.log}"
OUT="/tmp/nginx_report_$(date +%Y%m%d).html"

[[ ! -f "$LOG" ]] && { echo "日志文件不存在: $LOG"; exit 1; }

# 统计数据
total=$(wc -l < "$LOG")
uniq_ip=$(awk '{print $1}' "$LOG" | sort -u | wc -l)
err_4xx=$(awk '$9~/^4/{c++} END{print c+0}' "$LOG")
err_5xx=$(awk '$9~/^5/{c++} END{print c+0}' "$LOG")

# Top10 IP
top_ip=$(awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10)

# Top10 URL
top_url=$(awk '{print $7}' "$LOG" | sort | uniq -c | sort -rn | head -10)

# 状态码分布
status_dist=$(awk '{print $9}' "$LOG" | sort | uniq -c | sort -rn)

# 生成 HTML 报告
cat << HTMLEOF > "$OUT"
<!DOCTYPE html>
<html><head><meta charset="UTF-8">
<title>Nginx 报告</title>
<style>
body{font-family:sans-serif;background:#f5f5f5;margin:0;padding:20px}
.card{background:#fff;border-radius:8px;padding:20px;margin:16px 0;box-shadow:0 2px 8px rgba(0,0,0,.08)}
h1{color:#333} h2{color:#555;border-bottom:2px solid #4caf50;padding-bottom:8px}
.stats{display:flex;gap:20px;flex-wrap:wrap}
.stat{background:linear-gradient(135deg,#4caf50,#45a049);color:#fff;border-radius:8px;padding:16px 24px;text-align:center}
.stat .num{font-size:2rem;font-weight:700}
pre{background:#f8f8f8;border-left:4px solid #4caf50;padding:14px;overflow-x:auto;font-size:.85rem}
</style></head><body>
<h1>📊 Nginx 访问日志分析报告</h1>
<p>日志文件:$LOG  |  生成时间:$(date '+%Y-%m-%d %H:%M:%S')</p>
<div class="card">
  <h2>概况统计</h2>
  <div class="stats">
    <div class="stat"><div class="num">$total</div>总请求数</div>
    <div class="stat"><div class="num">$uniq_ip</div>独立IP</div>
    <div class="stat" style="background:linear-gradient(135deg,#ff9800,#f57c00)"><div class="num">$err_4xx</div>4xx错误</div>
    <div class="stat" style="background:linear-gradient(135deg,#f44336,#c62828)"><div class="num">$err_5xx</div>5xx错误</div>
  </div>
</div>
<div class="card"><h2>Top 10 IP</h2><pre>$top_ip</pre></div>
<div class="card"><h2>Top 10 URL</h2><pre>$top_url</pre></div>
<div class="card"><h2>状态码分布</h2><pre>$status_dist</pre></div>
</body></html>
HTMLEOF

echo "✓ 报告已生成: $OUT"
bash
4

🔔 服务监控告警脚本

持续监控服务,异常时发送告警通知

#!/usr/bin/env bash
# 服务监控告警 monitor.sh
# 部署建议:加入 crontab,每分钟执行一次

set -euo pipefail

ALERT_WEBHOOK="${WEBHOOK_URL:-}"  # 企业微信/钉钉 webhook URL
HOSTNAME=$(hostname)
LOG="/var/log/monitor.log"
STATE_DIR="/var/run/monitor"
mkdir -p "$STATE_DIR"

log()   { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG"; }
alert() {
    log "[ALERT] $*"
    if [[ -n "$ALERT_WEBHOOK" ]]; then
        curl -s -X POST "$ALERT_WEBHOOK" \
          -H 'Content-Type: application/json' \
          -d '{"msgtype":"text","text":{"content":"[告警] '"$HOSTNAME"': '"$*"'"}}' \
          >/dev/null 2>&1 || true
    fi
}

check_service() {
    local svc="$1"
    local state_file="$STATE_DIR/$svc.state"

    if ! systemctl is-active "$svc" >/dev/null 2>&1; then
        # 防重复告警:上次已告警则跳过
        if [[ ! -f "$state_file" ]]; then
            alert "服务 $svc 已停止!正在尝试重启..."
            systemctl start "$svc" >/dev/null 2>&1 || true
            touch "$state_file"
        fi
    else
        # 恢复后清除状态,发送恢复通知
        if [[ -f "$state_file" ]]; then
            alert "服务 $svc 已恢复正常"
            rm -f "$state_file"
        fi
    fi
}

check_disk() {
    local threshold=90
    while IFS= read -r line; do
        usage=$(awk '{print $5}' <<< "$line" | tr -d '%')
        mount=$(awk '{print $6}' <<< "$line")
        (( usage >= threshold )) && alert "磁盘告警: $mount 使用率 ${usage}%"
    done < <(df -h | grep '^/dev')
}

# 执行检查
for svc in sshd nginx mysqld; do
    check_service "$svc"
done
check_disk

log "巡检完成"
bash
5

📋 交互式运维管理菜单

集成常用运维操作的交互式菜单工具

#!/usr/bin/env bash
# 交互式运维菜单 ops_menu.sh

set -uo pipefail

# 颜色
R='\033[0;31m' G='\033[0;32m'
Y='\033[1;33m' B='\033[0;34m'
C='\033[0;36m' N='\033[0m'

header() {
    clear
    echo -e "${C}"
    echo "╔══════════════════════════════════════╗"
    echo "║       运维管理工具箱  v1.0           ║"
    echo "╠══════════════════════════════════════╣"
    printf "║  主机: %-29s ║\n" "$(hostname)"
    printf "║  IP:   %-29s ║\n" "$(hostname -I | awk '{print $1}')"
    printf "║  时间: %-29s ║\n" "$(date '+%Y-%m-%d %H:%M:%S')"
    echo "╚══════════════════════════════════════╝"
    echo -e "${N}"
}

main_menu() {
    header
    echo -e "  ${Y}请选择操作:${N}"
    echo "  ──────────────────────────────"
    echo -e "  ${G}1)${N} 系统资源概况"
    echo -e "  ${G}2)${N} 服务状态检查"
    echo -e "  ${G}3)${N} 磁盘使用情况"
    echo -e "  ${G}4)${N} 网络连接状态"
    echo -e "  ${G}5)${N} 查看系统日志(最近50行)"
    echo -e "  ${G}6)${N} 进程 Top 10"
    echo -e "  ${G}7)${N} 登录用户与历史"
    echo "  ──────────────────────────────"
    echo -e "  ${R}0)${N} 退出"
    echo
    read -rp "  请输入 [0-7]: " choice
}

while true; do
    main_menu
    case "$choice" in
        1) echo "--- CPU ---"; uptime; echo
           echo "--- 内存 ---"; free -h; echo
           echo "--- 负载 ---"; cat /proc/loadavg ;;
        2) for s in sshd nginx mysql firewalld; do
               printf "  %-15s" "$s"
               systemctl is-active "$s" 2>/dev/null || true
           done ;;
        3) df -hT | grep -v tmpfs ;;
        4) ss -tnp; echo; echo "ESTABLISHED:$(ss -tn | grep -c ESTAB || true)" ;;
        5) journalctl -n 50 --no-pager 2>/dev/null || tail -50 /var/log/syslog ;;
        6) ps aux --sort=-%cpu | head -11 ;;
        7) who; echo; last -10 ;;
        0) echo "再见!"; exit 0 ;;
        *) echo -e "${R}无效选项${N}" ;;
    esac
    read -rp "  按 Enter 返回菜单..."
done
bash
🏆

恭喜你完成了一周 Shell 脚本学习!

你已经系统学习了 Shell 脚本编程的全部核心知识,并完成了5个生产可用的实战项目。这些技能将在你的运维工作中发挥巨大作用!

🚀 环境入门 📦 变量字符串 🔀 流程控制 ⚙️ 函数数组 🔪 文本三剑客 🖥️ 系统编程 🏆 综合实战
📚
继续提升的学习方向
  • 学习 Python 自动化运维(更强大的字符串处理和网络能力)
  • 深入 Ansible 配置管理(Shell 脚本的替代与升级)
  • 学习 Git + CI/CD 将脚本版本化管理
  • 研究 Bash 性能优化和安全加固技巧
  • 探索 zsh/fish 等现代 Shell 的高级特性