✉ support@finalshell.com.cn 📖 返回首页

FinalShell自动化运维脚本编写教程:Shell脚本从入门到实战

FinalShell自动化运维脚本

引言:告别重复劳动,拥抱自动化运维

作为运维工程师,您是否经常面临这样的情况:每天重复执行相同的检查命令、手动部署应用到多台服务器、凌晨收到告警后匆忙登录服务器排查问题?这些重复性工作不仅耗费大量时间和精力,还容易因人为失误导致故障。自动化运维脚本是解决这些问题的关键。结合FinalShell强大的终端能力和命令片段管理功能,您可以轻松编写和管理各类自动化运维脚本,让机器替代人工完成重复劳动。

一、Shell脚本基础与FinalShell集成

1.1 在FinalShell中编写脚本

FinalShell提供了多种方式来编写和管理Shell脚本:

  • 内置编辑器:通过SFTP文件管理器双击远程脚本文件,直接在FinalShell内置编辑器中编辑
  • 命令片段:将常用脚本保存为命令片段,随时一键执行
  • 本地编辑+上传:在本地IDE中编写脚本,通过SFTP上传到服务器

1.2 脚本模板规范

编写高质量脚本的基础模板:

#!/bin/bash
# ============================================================
# 脚本名称: script_name.sh
# 功能描述: 脚本功能的简要描述
# 作者: Your Name
# 创建日期: 2026-03-15
# 版本: v1.0
# ============================================================

set -euo pipefail

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# 日志函数
log_info()  { echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $*" >&2; }

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本需要root权限运行"
        exit 1
    fi
}

# 主函数
main() {
    log_info "脚本开始执行..."
    # 在这里编写核心逻辑
    log_info "脚本执行完成"
}

main "$@"
Shell脚本编写

在FinalShell中编写和测试Shell自动化脚本

二、服务器自动巡检脚本

2.1 全面巡检脚本

每日自动巡检是运维的基本功,以下脚本覆盖了服务器健康检查的关键维度:

#!/bin/bash
# 服务器自动巡检脚本

REPORT_FILE="/var/log/inspection/$(date +%Y%m%d_%H%M%S).html"
HOSTNAME=$(hostname)
IP_ADDR=$(hostname -I | awk '{print $1}')

mkdir -p /var/log/inspection

generate_report() {
cat > $REPORT_FILE << 'HEADER'
<html><head><title>服务器巡检报告</title>
<style>body{font-family:sans-serif;margin:20px}
table{border-collapse:collapse;width:100%}
td,th{border:1px solid #ddd;padding:8px;text-align:left}
th{background:#4a90d9;color:#fff}
.warn{color:#f39c12}.error{color:#e74c3c}.ok{color:#27ae60}
</style></head><body>
HEADER

echo "<h1>服务器巡检报告</h1>" >> $REPORT_FILE
echo "<p>主机名: $HOSTNAME | IP: $IP_ADDR | 时间: $(date)</p>" >> $REPORT_FILE

# CPU检查
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.1f", $2+$4}')
echo "<h2>CPU状态</h2>" >> $REPORT_FILE
echo "<p>CPU使用率: ${CPU_USAGE}%</p>" >> $REPORT_FILE

# 内存检查
MEM_TOTAL=$(free -m | awk '/Mem:/{print $2}')
MEM_USED=$(free -m | awk '/Mem:/{print $3}')
MEM_PERCENT=$((MEM_USED * 100 / MEM_TOTAL))
echo "<h2>内存状态</h2>" >> $REPORT_FILE
echo "<p>内存使用: ${MEM_USED}MB / ${MEM_TOTAL}MB (${MEM_PERCENT}%)</p>" >> $REPORT_FILE

# 磁盘检查
echo "<h2>磁盘状态</h2><table><tr><th>挂载点</th><th>使用率</th><th>状态</th></tr>" >> $REPORT_FILE
df -h | grep "^/dev" | while read line; do
    MOUNT=$(echo $line | awk '{print $6}')
    USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
    STATUS="ok"
    [[ $USAGE -ge 80 ]] && STATUS="warn"
    [[ $USAGE -ge 90 ]] && STATUS="error"
    echo "<tr><td>${MOUNT}</td><td>${USAGE}%</td><td class='${STATUS}'>${STATUS}</td></tr>" >> $REPORT_FILE
done
echo "</table>" >> $REPORT_FILE

# 关键服务检查
echo "<h2>服务状态</h2><table><tr><th>服务</th><th>状态</th></tr>" >> $REPORT_FILE
for svc in nginx mysql docker redis; do
    if systemctl is-active --quiet $svc 2>/dev/null; then
        echo "<tr><td>${svc}</td><td class='ok'>运行中</td></tr>" >> $REPORT_FILE
    else
        echo "<tr><td>${svc}</td><td class='error'>已停止</td></tr>" >> $REPORT_FILE
    fi
done
echo "</table></body></html>" >> $REPORT_FILE

echo "巡检报告已生成: $REPORT_FILE"
}

generate_report

2.2 将巡检脚本加入FinalShell命令片段

在FinalShell中将巡检脚本保存为命令片段,实现一键巡检:

  1. 打开命令片段管理器
  2. 新建片段,命名为"服务器日常巡检"
  3. 粘贴脚本内容或输入脚本路径
  4. 设置快捷键(如Ctrl+Shift+I)
  5. 使用同步输入功能可同时在多台服务器执行巡检

三、自动化部署脚本

3.1 Java应用自动部署

#!/bin/bash
# Java应用自动部署脚本

APP_NAME="myapp"
APP_DIR="/opt/apps/${APP_NAME}"
BACKUP_DIR="/opt/backup/${APP_NAME}"
JAR_FILE="${APP_NAME}.jar"
LOG_FILE="/var/log/${APP_NAME}/deploy.log"
PID_FILE="${APP_DIR}/${APP_NAME}.pid"

deploy() {
    log_info "开始部署 ${APP_NAME}..."

    # 1. 创建备份
    if [[ -f "${APP_DIR}/${JAR_FILE}" ]]; then
        BACKUP_NAME="${JAR_FILE}.$(date +%Y%m%d%H%M%S).bak"
        mkdir -p ${BACKUP_DIR}
        cp "${APP_DIR}/${JAR_FILE}" "${BACKUP_DIR}/${BACKUP_NAME}"
        log_info "已备份旧版本: ${BACKUP_NAME}"
    fi

    # 2. 停止旧进程
    if [[ -f "${PID_FILE}" ]]; then
        OLD_PID=$(cat ${PID_FILE})
        if kill -0 ${OLD_PID} 2>/dev/null; then
            log_info "停止旧进程 PID: ${OLD_PID}"
            kill ${OLD_PID}
            sleep 5
            # 如果进程仍未退出,强制终止
            kill -0 ${OLD_PID} 2>/dev/null && kill -9 ${OLD_PID}
        fi
    fi

    # 3. 部署新版本(假设新包已通过SFTP上传到/tmp目录)
    cp /tmp/${JAR_FILE} ${APP_DIR}/${JAR_FILE}
    chmod +x ${APP_DIR}/${JAR_FILE}
    log_info "新版本已部署"

    # 4. 启动应用
    cd ${APP_DIR}
    nohup java -Xms512m -Xmx1024m \
        -jar ${JAR_FILE} \
        --spring.profiles.active=prod \
        > /var/log/${APP_NAME}/stdout.log 2>&1 &

    echo $! > ${PID_FILE}
    log_info "应用已启动,PID: $(cat ${PID_FILE})"

    # 5. 健康检查
    sleep 10
    for i in {1..6}; do
        if curl -sf http://localhost:8080/actuator/health > /dev/null 2>&1; then
            log_info "健康检查通过,部署成功!"
            return 0
        fi
        log_warn "等待应用启动... (${i}/6)"
        sleep 5
    done

    log_error "健康检查失败,准备回滚..."
    rollback
    return 1
}

rollback() {
    log_warn "开始回滚..."
    LATEST_BACKUP=$(ls -t ${BACKUP_DIR}/*.bak 2>/dev/null | head -1)
    if [[ -n "${LATEST_BACKUP}" ]]; then
        # 停止当前进程
        [[ -f "${PID_FILE}" ]] && kill $(cat ${PID_FILE}) 2>/dev/null
        sleep 3
        # 恢复备份
        cp "${LATEST_BACKUP}" "${APP_DIR}/${JAR_FILE}"
        # 重新启动
        cd ${APP_DIR}
        nohup java -Xms512m -Xmx1024m -jar ${JAR_FILE} --spring.profiles.active=prod > /var/log/${APP_NAME}/stdout.log 2>&1 &
        echo $! > ${PID_FILE}
        log_info "回滚完成,PID: $(cat ${PID_FILE})"
    else
        log_error "没有找到可用的备份文件"
    fi
}

deploy
自动化部署流程

通过FinalShell执行自动化部署,支持一键回滚

3.2 前端应用部署脚本

#!/bin/bash
# 前端应用自动部署脚本

WEB_ROOT="/var/www/myapp"
BACKUP_DIR="/var/www/backup"
NGINX_CONF="/etc/nginx/conf.d/myapp.conf"

deploy_frontend() {
    log_info "开始部署前端应用..."

    # 备份当前版本
    BACKUP_NAME="myapp_$(date +%Y%m%d%H%M%S)"
    mkdir -p ${BACKUP_DIR}
    tar czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" -C /var/www myapp/
    log_info "当前版本已备份"

    # 解压新版本(假设已上传到/tmp)
    rm -rf ${WEB_ROOT}/*
    tar xzf /tmp/dist.tar.gz -C ${WEB_ROOT}/
    log_info "新版本已解压"

    # 设置正确的文件权限
    chown -R nginx:nginx ${WEB_ROOT}
    chmod -R 755 ${WEB_ROOT}

    # 测试Nginx配置
    nginx -t
    if [[ $? -eq 0 ]]; then
        nginx -s reload
        log_info "Nginx配置已重载,部署成功!"
    else
        log_error "Nginx配置测试失败"
        # 回滚
        tar xzf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" -C /var/www/
        nginx -s reload
        log_warn "已回滚到上一版本"
    fi

    # 清理30天前的备份
    find ${BACKUP_DIR} -name "myapp_*.tar.gz" -mtime +30 -delete
}

deploy_frontend

四、日志分析与监控脚本

4.1 Nginx日志分析脚本

#!/bin/bash
# Nginx访问日志实时分析脚本

LOG_FILE="/var/log/nginx/access.log"

echo "===== Nginx日志分析报告 ====="
echo "分析时间: $(date)"
echo ""

# 今日请求总量
TODAY=$(date +%d/%b/%Y)
TOTAL=$(grep "${TODAY}" ${LOG_FILE} | wc -l)
echo "今日请求总量: ${TOTAL}"

# TOP 10 访问IP
echo ""
echo "===== TOP 10 访问IP ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $1}' | sort | uniq -c | sort -rn | head -10 | \
while read count ip; do
    printf "  %-16s %6d 次\n" "$ip" "$count"
done

# TOP 10 请求URL
echo ""
echo "===== TOP 10 请求URL ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $7}' | sort | uniq -c | sort -rn | head -10 | \
while read count url; do
    printf "  %-40s %6d 次\n" "$url" "$count"
done

# HTTP状态码统计
echo ""
echo "===== HTTP状态码分布 ====="
grep "${TODAY}" ${LOG_FILE} | awk '{print $9}' | sort | uniq -c | sort -rn | \
while read count code; do
    printf "  HTTP %s: %6d 次\n" "$code" "$count"
done

# 错误请求(4xx/5xx)
ERROR_COUNT=$(grep "${TODAY}" ${LOG_FILE} | awk '$9 >= 400 {print $0}' | wc -l)
echo ""
echo "错误请求总数(4xx+5xx): ${ERROR_COUNT}"

# 带宽统计
BANDWIDTH=$(grep "${TODAY}" ${LOG_FILE} | awk '{sum+=$10} END {printf "%.2f MB", sum/1024/1024}')
echo "今日带宽消耗: ${BANDWIDTH}"

4.2 异常告警脚本

#!/bin/bash
# 系统异常实时告警脚本

ALERT_LOG="/var/log/alert.log"
CHECK_INTERVAL=60

monitor_system() {
    while true; do
        TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

        # 检查CPU使用率
        CPU=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%.0f", $2+$4}')
        if [[ $CPU -gt 80 ]]; then
            echo "[${TIMESTAMP}] ALERT: CPU使用率过高 ${CPU}%" | tee -a $ALERT_LOG
        fi

        # 检查内存使用率
        MEM=$(free | awk '/Mem:/{printf "%.0f", $3/$2*100}')
        if [[ $MEM -gt 85 ]]; then
            echo "[${TIMESTAMP}] ALERT: 内存使用率过高 ${MEM}%" | tee -a $ALERT_LOG
        fi

        # 检查磁盘使用率
        df -h | grep "^/dev" | while read line; do
            USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
            MOUNT=$(echo $line | awk '{print $6}')
            if [[ $USAGE -gt 90 ]]; then
                echo "[${TIMESTAMP}] CRITICAL: 磁盘 ${MOUNT} 使用率 ${USAGE}%" | tee -a $ALERT_LOG
            fi
        done

        # 检查关键服务
        for svc in nginx mysql redis; do
            if ! systemctl is-active --quiet $svc 2>/dev/null; then
                echo "[${TIMESTAMP}] CRITICAL: 服务 ${svc} 已停止!尝试重启..." | tee -a $ALERT_LOG
                systemctl restart $svc
                sleep 3
                if systemctl is-active --quiet $svc; then
                    echo "[${TIMESTAMP}] INFO: 服务 ${svc} 已成功重启" | tee -a $ALERT_LOG
                else
                    echo "[${TIMESTAMP}] FATAL: 服务 ${svc} 重启失败!" | tee -a $ALERT_LOG
                fi
            fi
        done

        sleep $CHECK_INTERVAL
    done
}

monitor_system
日志分析与告警

通过自动化脚本实现日志分析与异常实时告警

五、定时任务管理

5.1 Crontab配置模板

通过FinalShell编辑crontab,设置定时自动执行脚本:

# 编辑定时任务
crontab -e

# ============ 定时任务配置 ============
# 每日凌晨2点执行服务器巡检
0 2 * * * /opt/scripts/inspection.sh >> /var/log/cron/inspection.log 2>&1

# 每6小时执行一次数据库备份
0 */6 * * * /opt/scripts/db_backup.sh >> /var/log/cron/backup.log 2>&1

# 每天凌晨3点清理过期日志
0 3 * * * /opt/scripts/log_cleanup.sh >> /var/log/cron/cleanup.log 2>&1

# 每5分钟执行一次系统监控
*/5 * * * * /opt/scripts/monitor.sh >> /var/log/cron/monitor.log 2>&1

# 每周日凌晨执行全量备份
0 1 * * 0 /opt/scripts/full_backup.sh >> /var/log/cron/full_backup.log 2>&1

# 每月1号生成月度报告
0 8 1 * * /opt/scripts/monthly_report.sh >> /var/log/cron/report.log 2>&1

5.2 日志清理脚本

#!/bin/bash
# 自动日志清理脚本

LOG_DIRS=(
    "/var/log/nginx"
    "/var/log/mysql"
    "/var/log/myapp"
    "/var/log/inspection"
)

RETENTION_DAYS=30

for dir in "${LOG_DIRS[@]}"; do
    if [[ -d "$dir" ]]; then
        COUNT=$(find "$dir" -type f -name "*.log" -mtime +${RETENTION_DAYS} | wc -l)
        if [[ $COUNT -gt 0 ]]; then
            find "$dir" -type f -name "*.log" -mtime +${RETENTION_DAYS} -delete
            echo "已清理 ${dir} 中 ${COUNT} 个过期日志文件"
        fi
        # 压缩7天前的日志
        find "$dir" -type f -name "*.log" -mtime +7 ! -name "*.gz" -exec gzip {} \;
    fi
done

# 清理系统日志
journalctl --vacuum-time=30d 2>/dev/null
echo "日志清理完成: $(date)"

六、脚本管理最佳实践

6.1 脚本版本管理

  • 使用Git管理脚本:在服务器上用Git仓库管理所有运维脚本
  • 添加版本标识:每个脚本头部注明版本号和修改记录
  • 代码审核:重要脚本修改需经过同事Review
  • FinalShell同步:通过FinalShell的SFTP功能保持本地和远程脚本同步

6.2 脚本安全规范

  • 最小权限原则:脚本只申请必要的执行权限
  • 敏感信息保护:密码和密钥不硬编码在脚本中,使用环境变量或配置文件
  • 操作确认机制:危险操作(如删除、重启)增加确认提示
  • 详细日志记录:每个关键操作都记录日志,便于问题追溯
  • 错误处理:使用set -euo pipefail确保错误能被捕获

总结

自动化运维是现代运维工程师的核心能力。通过FinalShell强大的终端能力和命令片段管理功能,结合本文介绍的各类实战脚本模板,您可以快速构建起一套完整的自动化运维体系。从日常巡检到应用部署,从日志分析到异常告警,自动化脚本可以显著提升运维效率,减少人为错误,让您从繁琐的重复劳动中解放出来,专注于更有价值的架构设计和技术创新。

立即下载最新版FinalShell,开始您的自动化运维之旅!