为什么我收藏了这些脚本
做运维这些年,我积累了一套"瑞士军刀"级别的Shell脚本。每拿到一台新服务器,第一时间就是把这些脚本部署上去。今天把最实用的10个分享出来。
每个脚本我都在生产环境跑过,可以直接复制使用。
脚本1:服务器初始化
新服务器拿到手,一键完成基础配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| #!/bin/bash
# init_server.sh - 新服务器初始化脚本
set -e
echo "===== 服务器初始化开始 ====="
# 更新系统
echo "[1/6] 更新系统..."
apt update && apt upgrade -y
# 安装常用工具
echo "[2/6] 安装常用工具..."
apt install -y curl wget git vim htop unzip fail2ban ufw
# 配置时区
echo "[3/6] 配置时区..."
timedatectl set-timezone Asia/Shanghai
echo "当前时间: $(date)"
# 配置防火墙
echo "[4/6] 配置防火墙..."
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
# 配置fail2ban
echo "[5/6] 配置fail2ban..."
systemctl enable fail2ban
systemctl start fail2ban
# 优化系统参数
echo "[6/6] 优化内核参数..."
cat >> /etc/sysctl.conf <<EOF
# 网络优化
net.core.somaxconn = 65535
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_fin_timeout = 30
EOF
sysctl -p
echo "===== 初始化完成 ====="
|
脚本2:自动备份(MySQL + 文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| #!/bin/bash
# backup.sh - 每日自动备份脚本
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup"
RETENTION_DAYS=7
LOG="/var/log/backup.log"
# MySQL配置
DB_USER="root"
DB_PASS="your_password"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG
}
mkdir -p $BACKUP_DIR/{mysql,files}
# 备份MySQL
log "开始备份MySQL..."
mysqldump -u$DB_USER -p$DB_PASS --all-databases 2>/dev/null | gzip > $BACKUP_DIR/mysql/all_db_$DATE.sql.gz
if [ $? -eq 0 ]; then
SIZE=$(ls -lh $BACKUP_DIR/mysql/all_db_$DATE.sql.gz | awk '{print $5}')
log "MySQL备份成功: $SIZE"
else
log "MySQL备份失败!"
fi
# 备份网站文件
log "开始备份文件..."
tar -czf $BACKUP_DIR/files/www_$DATE.tar.gz /var/www/ 2>/dev/null
if [ $? -eq 0 ]; then
SIZE=$(ls -lh $BACKUP_DIR/files/www_$DATE.tar.gz | awk '{print $5}')
log "文件备份成功: $SIZE"
else
log "文件备份失败!"
fi
# 清理旧备份
log "清理${RETENTION_DAYS}天前的备份..."
find $BACKUP_DIR -name "*.gz" -mtime +$RETENTION_DAYS -delete
REMAINING=$(find $BACKUP_DIR -name "*.gz" | wc -l)
log "当前备份文件数: $REMAINING"
log "备份完成"
|
运行效果:
1
2
3
4
5
6
7
8
9
| $ chmod +x backup.sh
$ ./backup.sh
[2026-02-03 03:00:01] 开始备份MySQL...
[2026-02-03 03:00:15] MySQL备份成功: 23M
[2026-02-03 03:00:15] 开始备份文件...
[2026-02-03 03:00:45] 文件备份成功: 156M
[2026-02-03 03:00:45] 清理7天前的备份...
[2026-02-03 03:00:46] 当前备份文件数: 14
[2026-02-03 03:00:46] 备份完成
|
脚本3:磁盘空间报警
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #!/bin/bash
# disk_alert.sh - 磁盘空间监控
THRESHOLD=80
ALERT_EMAIL="[email protected]"
df -h | awk 'NR>1' | while read line; do
USAGE=$(echo $line | awk '{print $5}' | tr -d '%')
MOUNT=$(echo $line | awk '{print $6}')
AVAIL=$(echo $line | awk '{print $4}')
if [ -n "$USAGE" ] && [ "$USAGE" -gt "$THRESHOLD" ] 2>/dev/null; then
MSG="警告: $MOUNT 使用率 ${USAGE}%,剩余 $AVAIL"
echo "$MSG"
echo "$MSG" | mail -s "磁盘报警 - $(hostname)" $ALERT_EMAIL 2>/dev/null
fi
done
|
脚本4:批量SSH执行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #!/bin/bash
# batch_ssh.sh - 批量在多台服务器执行命令
SERVERS=(
"[email protected]"
"[email protected]"
"[email protected]"
)
CMD="$@"
if [ -z "$CMD" ]; then
echo "用法: $0 <command>"
echo "示例: $0 uptime"
exit 1
fi
for SERVER in "${SERVERS[@]}"; do
echo "===== $SERVER ====="
ssh -o ConnectTimeout=5 $SERVER "$CMD" 2>&1
echo ""
done
|
1
2
3
4
5
6
7
8
| $ ./batch_ssh.sh "uptime && df -h /"
===== [email protected] =====
10:00:00 up 30 days, 3:22, 1 user, load average: 0.15, 0.10, 0.08
/dev/vda1 40G 12G 26G 32% /
===== [email protected] =====
10:00:00 up 45 days, 7:15, 1 user, load average: 0.52, 0.38, 0.31
/dev/vda1 40G 25G 13G 66% /
|
脚本5:网站可用性监控
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| #!/bin/bash
# site_monitor.sh - 网站可用性监控
SITES=(
"https://example.com"
"https://blog.example.com"
"https://api.example.com/health"
)
LOG="/var/log/site_monitor.log"
for SITE in "${SITES[@]}"; do
HTTP_CODE=$(curl -o /dev/null -s -w "%{http_code}" --connect-timeout 10 "$SITE")
RESPONSE_TIME=$(curl -o /dev/null -s -w "%{time_total}" --connect-timeout 10 "$SITE")
if [ "$HTTP_CODE" -ne 200 ]; then
echo "[$(date)] FAIL: $SITE 返回 $HTTP_CODE" | tee -a $LOG
# 可以在这里加钉钉/微信通知
else
echo "[$(date)] OK: $SITE (${RESPONSE_TIME}s)" | tee -a $LOG
fi
done
|
| Crontab配置 | 频率 | 说明 |
|---|
*/1 * * * * | 每分钟 | 核心业务 |
*/5 * * * * | 每5分钟 | 普通站点 |
*/15 * * * * | 每15分钟 | 非关键服务 |
脚本6:日志切割与清理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #!/bin/bash
# log_rotate.sh - 日志管理脚本
LOG_DIR="/var/log/myapp"
KEEP_DAYS=30
# 按日期切割当前日志
TODAY=$(date +%Y%m%d)
for log in $LOG_DIR/*.log; do
if [ -f "$log" ]; then
mv "$log" "${log}.$TODAY"
gzip "${log}.$TODAY"
touch "$log"
fi
done
# 重载应用使其使用新日志文件
systemctl reload nginx 2>/dev/null
# 删除过期日志
find $LOG_DIR -name "*.gz" -mtime +$KEEP_DAYS -delete
echo "日志切割完成,已清理${KEEP_DAYS}天前的日志"
|
脚本7:Docker一键部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| #!/bin/bash
# deploy.sh - Docker应用部署脚本
set -e
APP_DIR="/opt/myapp"
IMAGE_NAME="myapp"
CONTAINER_NAME="myapp-web"
cd $APP_DIR
echo "=== 拉取最新代码 ==="
git pull origin main
echo "=== 构建Docker镜像 ==="
docker build -t $IMAGE_NAME:latest .
echo "=== 停止旧容器 ==="
docker stop $CONTAINER_NAME 2>/dev/null || true
docker rm $CONTAINER_NAME 2>/dev/null || true
echo "=== 启动新容器 ==="
docker run -d \
--name $CONTAINER_NAME \
--restart=always \
-p 3000:3000 \
-v $APP_DIR/data:/app/data \
$IMAGE_NAME:latest
echo "=== 清理旧镜像 ==="
docker image prune -f
echo "=== 部署完成 ==="
docker ps | grep $CONTAINER_NAME
|
脚本8:系统资源报告
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| #!/bin/bash
# system_report.sh - 每日系统报告
echo "=============================="
echo " 系统资源报告 - $(date '+%Y-%m-%d')"
echo " 主机: $(hostname)"
echo "=============================="
echo -e "\n[运行时间]"
uptime
echo -e "\n[CPU使用 Top5]"
ps aux --sort=-%cpu | head -6 | awk '{printf "%-10s %-6s %-6s %s\n", $1, $3"%", $4"%", $11}'
echo -e "\n[内存]"
free -h
echo -e "\n[磁盘]"
df -h | grep -E '^/dev/'
echo -e "\n[网络连接统计]"
ss -s | head -4
echo -e "\n[最近登录]"
last -5
echo "=============================="
|
脚本9:安全审计检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| #!/bin/bash
# security_check.sh - 安全审计脚本
echo "===== 安全审计报告 ====="
echo "时间: $(date)"
echo -e "\n[1] SSH暴力破解尝试 (Top 10 IP)"
grep "Failed password" /var/log/auth.log 2>/dev/null | \
awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10
echo -e "\n[2] 当前登录用户"
who
echo -e "\n[3] 有sudo权限的用户"
grep -E '^sudo:' /etc/group | cut -d: -f4
echo -e "\n[4] 监听端口"
ss -tlnp | awk 'NR>1 {print $4, $6}'
echo -e "\n[5] 最近修改的系统文件"
find /etc -mtime -7 -type f 2>/dev/null | head -20
echo -e "\n[6] 防火墙状态"
ufw status 2>/dev/null || iptables -L -n 2>/dev/null | head -10
echo "===== 审计完成 ====="
|
脚本10:一键安装Docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| #!/bin/bash
# install_docker.sh - 一键安装Docker和Docker Compose
set -e
echo "===== 安装Docker ====="
# 检查是否已安装
if command -v docker &> /dev/null; then
echo "Docker已安装: $(docker --version)"
exit 0
fi
# 安装依赖
apt update
apt install -y ca-certificates curl gnupg
# 添加Docker仓库
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 启动服务
systemctl enable --now docker
# 验证
docker --version
docker compose version
echo "===== Docker安装完成 ====="
|
使用建议
| 脚本 | 建议触发方式 | Crontab示例 |
|---|
| 备份脚本 | 每日凌晨 | 0 3 * * * |
| 磁盘报警 | 每小时 | 0 * * * * |
| 网站监控 | 每5分钟 | */5 * * * * |
| 日志清理 | 每周 | 0 4 * * 0 |
| 系统报告 | 每日早上 | 0 8 * * * |
| 安全审计 | 每周 | 0 9 * * 1 |
总结
这10个脚本覆盖了运维最常见的场景。建议在服务器上创建一个/root/scripts/目录专门存放这些脚本,配合Crontab定时执行。
Shell脚本基础语法可以参考Shell脚本编程入门。定时任务的详细配置请看Crontab定时任务全攻略。