运维工作重复性高,写好脚本能省很多时间。
这篇分享10个实用的Shell脚本,拿来就能用。
一、服务器巡检脚本
#!/bin/bash
# server_check.sh - 服务器巡检echo "==================== 服务器巡检报告 ===================="
echo "检查时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "主机名: $(hostname)"
echo ""# CPU使用率
echo "--- CPU使用率 ---"
top -bn1 | grep "Cpu(s)" | awk '{print "使用率: " 100-$8 "%"}'
echo ""# 内存使用
echo "--- 内存使用 ---"
free -h | awk 'NR==2{printf "总内存: %s, 已用: %s, 使用率: %.2f%%\n", $2, $3, $3/$2*100}'
echo ""# 磁盘使用
echo "--- 磁盘使用 ---"
df -h | awk '$5+0 > 70 {print $0}'
echo ""# 负载
echo "--- 系统负载 ---"
uptime | awk -F'load average:' '{print "负载: " $2}'
echo ""# 进程数
echo "--- 进程统计 ---"
echo "总进程数: $(ps aux | wc -l)"
echo "僵尸进程: $(ps aux | grep -c 'Z')"
echo ""# 网络连接
echo "--- 网络连接 ---"
ss -s | head -5
echo ""echo "==================== 巡检完成 ===================="
二、日志清理脚本
#!/bin/bash
# log_cleaner.sh - 清理过期日志LOG_DIRS=("/var/log/app""/var/log/nginx""/home/app/logs"
)DAYS=7 # 保留天数for dir in "${LOG_DIRS[@]}"; doif [ -d "$dir" ]; thenecho "清理目录: $dir"# 删除N天前的日志find "$dir" -name "*.log*" -type f -mtime +$DAYS -deletefind "$dir" -name "*.gz" -type f -mtime +$DAYS -delete# 清空大于100M的当前日志find "$dir" -name "*.log" -type f -size +100M -exec truncate -s 0 {} \;echo "完成"fi
doneecho "日志清理完成: $(date)"
加入crontab:
0 2 * * * /root/scripts/log_cleaner.sh >> /var/log/log_cleaner.log 2>&1
三、服务监控并自动重启
#!/bin/bash
# service_monitor.sh - 服务监控SERVICE_NAME="myapp"
CHECK_URL="http://localhost:8080/health"
MAX_RETRY=3
ALERT_EMAIL="admin@example.com"check_service() {# HTTP健康检查http_code=$(curl -s -o /dev/null -w "%{http_code}" "$CHECK_URL" --connect-timeout 5)if [ "$http_code" == "200" ]; thenreturn 0elsereturn 1fi
}restart_service() {echo "$(date) - 重启服务..."systemctl restart "$SERVICE_NAME"sleep 10
}send_alert() {local message=$1echo "$message" | mail -s "服务告警: $SERVICE_NAME" "$ALERT_EMAIL"# 或者用钉钉/企业微信webhook
}# 主逻辑
retry=0
while [ $retry -lt $MAX_RETRY ]; doif check_service; thenecho "$(date) - 服务正常"exit 0fiecho "$(date) - 服务异常,第 $((retry+1)) 次检查"retry=$((retry+1))sleep 5
done# 达到重试次数,尝试重启
restart_serviceif check_service; thensend_alert "服务自动重启成功"
elsesend_alert "服务重启失败,请人工介入!"
fi
四、批量SSH执行命令
#!/bin/bash
# batch_ssh.sh - 批量执行命令SERVERS=("192.168.1.101""192.168.1.102""192.168.1.103"
)
SSH_USER="root"
SSH_KEY="~/.ssh/id_rsa"# 要执行的命令
COMMAND=$1if [ -z "$COMMAND" ]; thenecho "用法: $0 '命令'"echo "示例: $0 'df -h'"exit 1
fifor server in "${SERVERS[@]}"; doecho "========== $server =========="ssh -i "$SSH_KEY" -o ConnectTimeout=5 "$SSH_USER@$server" "$COMMAND"echo ""
done
使用:
./batch_ssh.sh "df -h"
./batch_ssh.sh "systemctl status nginx"
五、MySQL备份脚本
#!/bin/bash
# mysql_backup.sh - MySQL备份# 配置
MYSQL_USER="backup"
MYSQL_PASS="password"
MYSQL_HOST="localhost"
BACKUP_DIR="/data/backup/mysql"
KEEP_DAYS=7# 创建备份目录
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DIR/$DATE"
mkdir -p "$BACKUP_PATH"# 获取所有数据库
DATABASES=$(mysql -h"$MYSQL_HOST" -u"$MYSQL_USER" -p"$MYSQL_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|sys)")# 备份每个数据库
for db in $DATABASES; doecho "备份数据库: $db"mysqldump -h"$MYSQL_HOST" -u"$MYSQL_USER" -p"$MYSQL_PASS" \--single-transaction --routines --triggers \"$db" | gzip > "$BACKUP_PATH/${db}.sql.gz"
done# 删除过期备份
find "$BACKUP_DIR" -type d -mtime +$KEEP_DAYS -exec rm -rf {} \; 2>/dev/nullecho "备份完成: $BACKUP_PATH"
echo "备份大小: $(du -sh $BACKUP_PATH | awk '{print $1}')"
六、端口扫描脚本
#!/bin/bash
# port_scan.sh - 端口扫描TARGET=$1
START_PORT=${2:-1}
END_PORT=${3:-1000}if [ -z "$TARGET" ]; thenecho "用法: $0 <目标IP> [起始端口] [结束端口]"echo "示例: $0 192.168.1.1 1 1000"exit 1
fiecho "扫描 $TARGET 端口 $START_PORT-$END_PORT"
echo "开放的端口:"for port in $(seq $START_PORT $END_PORT); do(echo >/dev/tcp/$TARGET/$port) 2>/dev/null && echo "$port"
doneecho "扫描完成"
七、文件同步脚本
#!/bin/bash
# file_sync.sh - 文件同步SOURCE_DIR="/data/app"
TARGET_SERVERS=("root@192.168.1.102:/data/app""root@192.168.1.103:/data/app"
)
EXCLUDE_FILE="/root/scripts/rsync_exclude.txt"# 排除文件列表
cat > "$EXCLUDE_FILE" << EOF
*.log
*.tmp
*.cache
node_modules/
.git/
EOFfor target in "${TARGET_SERVERS[@]}"; doecho "同步到: $target"rsync -avz --delete \--exclude-from="$EXCLUDE_FILE" \"$SOURCE_DIR/" "$target"echo "完成"
done
八、进程监控脚本
#!/bin/bash
# process_monitor.sh - 进程监控# 监控的进程列表
PROCESSES=("java""nginx""redis-server""mysqld"
)echo "进程监控报告 - $(date)"
echo "======================================"for proc in "${PROCESSES[@]}"; dopid=$(pgrep -f "$proc" | head -1)if [ -n "$pid" ]; then# 获取进程信息cpu=$(ps -p $pid -o %cpu | tail -1)mem=$(ps -p $pid -o %mem | tail -1)printf "%-15s PID:%-8s CPU:%-6s MEM:%-6s [运行中]\n" "$proc" "$pid" "$cpu%" "$mem%"elseprintf "%-15s %-8s %-6s %-6s [未运行!]\n" "$proc" "-" "-" "-"fi
done
九、磁盘空间告警脚本
#!/bin/bash
# disk_alert.sh - 磁盘告警THRESHOLD=80 # 告警阈值
WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=xxx"# 检查磁盘使用率
alert_msg=""
while read -r line; dousage=$(echo "$line" | awk '{print $5}' | tr -d '%')mount=$(echo "$line" | awk '{print $6}')if [ "$usage" -gt "$THRESHOLD" ]; thenalert_msg="${alert_msg}磁盘 $mount 使用率 ${usage}%\n"fi
done < <(df -h | tail -n +2)# 发送告警
if [ -n "$alert_msg" ]; thenhostname=$(hostname)timestamp=$(date '+%Y-%m-%d %H:%M:%S')# 钉钉告警curl -s "$WEBHOOK_URL" \-H 'Content-Type: application/json' \-d "{\"msgtype\": \"text\",\"text\": {\"content\": \"磁盘告警\n主机: $hostname\n时间: $timestamp\n$alert_msg\"}}"
fi
十、一键部署脚本
#!/bin/bash
# deploy.sh - 一键部署APP_NAME="myapp"
DEPLOY_PATH="/data/app"
BACKUP_PATH="/data/backup"
JAR_FILE="$DEPLOY_PATH/$APP_NAME.jar"
LOG_FILE="/var/log/$APP_NAME/app.log"# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }# 1. 备份
log_info "备份旧版本..."
if [ -f "$JAR_FILE" ]; thencp "$JAR_FILE" "$BACKUP_PATH/${APP_NAME}_$(date +%Y%m%d_%H%M%S).jar"
fi# 2. 停止服务
log_info "停止服务..."
pid=$(pgrep -f "$APP_NAME.jar")
if [ -n "$pid" ]; thenkill -15 "$pid"sleep 5# 强制killif pgrep -f "$APP_NAME.jar" > /dev/null; thenkill -9 "$pid"fi
fi# 3. 部署新版本
log_info "部署新版本..."
# 这里可以从Jenkins/Nexus/OSS下载新的jar包
# wget -O "$JAR_FILE" "http://xxx/myapp.jar"# 4. 启动服务
log_info "启动服务..."
nohup java -Xms1g -Xmx1g -jar "$JAR_FILE" > "$LOG_FILE" 2>&1 &# 5. 健康检查
log_info "健康检查..."
sleep 10
for i in {1..12}; doif curl -s http://localhost:8080/health > /dev/null; thenlog_info "部署成功!"exit 0fisleep 5
donelog_error "健康检查失败!"
exit 1
十一、远程脚本管理
脚本写好了,怎么同步到多台服务器?
我用星空组网工具把本地和所有服务器连起来,用rsync同步:
# 同步脚本到所有服务器
for server in 192.168.188.{10..20}; dorsync -avz ~/scripts/ root@$server:/root/scripts/
done
调试脚本也方便,本地改完直接同步过去执行:
scp disk_alert.sh root@192.168.188.10:/root/scripts/
ssh root@192.168.188.10 "bash /root/scripts/disk_alert.sh"
比用跳板机效率高多了。
总结
| 脚本 | 用途 | 建议执行方式 |
|---|---|---|
| 服务器巡检 | 日常巡检 | 每天定时 |
| 日志清理 | 清理过期日志 | 每天凌晨 |
| 服务监控 | 自动重启 | 每分钟 |
| MySQL备份 | 数据库备份 | 每天凌晨 |
| 磁盘告警 | 容量告警 | 每10分钟 |
| 一键部署 | 应用发布 | 手动执行 |
Shell脚本的核心:把重复的工作自动化。
有问题评论区交流~