Bash Shell 脚本编程完整教程
Bash(Bourne Again Shell)是 Linux 系统上最常用的命令行解释器和脚本语言。掌握 Bash 脚本编程可以帮助你在搬瓦工 VPS 上实现服务器管理的自动化,从批量文件处理到系统监控、定时备份,几乎所有运维任务都能通过 Bash 脚本高效完成。本文将从基础语法讲起,系统讲解变量、条件判断、循环、函数、数组等核心知识点。
一、第一个 Bash 脚本
创建一个名为 hello.sh 的脚本文件:
#!/bin/bash
# 这是一个简单的 Bash 脚本
echo "Hello, 搬瓦工 VPS!"
echo "当前时间: $(date)"
echo "系统负载: $(uptime)"
第一行 #!/bin/bash 称为 Shebang,告诉系统使用 Bash 来解释执行这个脚本。赋予执行权限后即可运行:
chmod +x hello.sh
./hello.sh
二、变量与数据类型
2.1 变量定义与使用
Bash 中定义变量时等号两边不能有空格,引用变量使用 $ 符号:
#!/bin/bash
# 变量定义
NAME="搬瓦工"
PORT=22
DATA_DIR="/var/data"
# 使用变量
echo "服务器名称: $NAME"
echo "SSH 端口: ${PORT}"
echo "数据目录: ${DATA_DIR}"
# 只读变量
readonly SERVER_IP="192.168.1.1"
# 删除变量
unset PORT
2.2 特殊变量
Bash 提供了多种特殊变量用于脚本编程:
#!/bin/bash
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "所有参数: $@"
echo "参数个数: $#"
echo "上条命令返回值: $?"
echo "当前进程 PID: $$"
echo "后台进程 PID: $!"
2.3 字符串操作
Bash 中字符串操作非常灵活,支持拼接、截取、替换等功能:
#!/bin/bash
STR="Hello World Bash Scripting"
# 字符串长度
echo "长度: ${#STR}"
# 子串截取(从位置 6 开始,取 5 个字符)
echo "截取: ${STR:6:5}"
# 字符串替换
echo "替换: ${STR/World/Linux}"
# 删除前缀(最短匹配)
FILE="/var/log/syslog.log"
echo "文件名: ${FILE##*/}"
# 删除后缀(最短匹配)
echo "目录: ${FILE%/*}"
# 默认值
echo "未设置变量: ${UNDEFINED:-默认值}"
三、条件判断
3.1 if-else 语句
#!/bin/bash
DISK_USAGE=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 90 ]; then
echo "警告: 磁盘使用率超过 90%,当前 ${DISK_USAGE}%"
elif [ "$DISK_USAGE" -gt 70 ]; then
echo "提示: 磁盘使用率较高,当前 ${DISK_USAGE}%"
else
echo "正常: 磁盘使用率 ${DISK_USAGE}%"
fi
3.2 常用测试条件
文件测试和数值比较是脚本中最常用的条件判断:
#!/bin/bash
# 文件测试
FILE="/etc/nginx/nginx.conf"
if [ -f "$FILE" ]; then
echo "配置文件存在"
fi
if [ -d "/var/log" ]; then
echo "日志目录存在"
fi
if [ -r "$FILE" ]; then
echo "文件可读"
fi
# 数值比较:-eq 等于, -ne 不等于, -gt 大于, -lt 小于, -ge 大于等于, -le 小于等于
A=10
B=20
if [ "$A" -lt "$B" ]; then
echo "$A 小于 $B"
fi
# 字符串比较
STR1="hello"
STR2="world"
if [ "$STR1" != "$STR2" ]; then
echo "字符串不相等"
fi
# 使用 [[ ]] 支持正则匹配
if [[ "$STR1" =~ ^hel ]]; then
echo "匹配成功"
fi
3.3 case 语句
#!/bin/bash
read -p "请选择操作 (start/stop/restart): " ACTION
case "$ACTION" in
start)
echo "启动服务..."
systemctl start nginx
;;
stop)
echo "停止服务..."
systemctl stop nginx
;;
restart)
echo "重启服务..."
systemctl restart nginx
;;
*)
echo "无效操作: $ACTION"
echo "用法: start|stop|restart"
exit 1
;;
esac
四、循环结构
4.1 for 循环
#!/bin/bash
# 遍历列表
for SERVER in web01 web02 web03 db01; do
echo "正在检查: $SERVER"
ping -c 1 "$SERVER" &>/dev/null && echo " 在线" || echo " 离线"
done
# C 风格 for 循环
for ((i=1; i<=10; i++)); do
echo "第 $i 次循环"
done
# 遍历文件
for FILE in /var/log/*.log; do
SIZE=$(du -sh "$FILE" | awk '{print $1}')
echo "$FILE: $SIZE"
done
4.2 while 循环
#!/bin/bash
# 监控系统负载
while true; do
LOAD=$(cat /proc/loadavg | awk '{print $1}')
echo "$(date '+%Y-%m-%d %H:%M:%S') 负载: $LOAD"
if (( $(echo "$LOAD > 5.0" | bc -l) )); then
echo "警告: 系统负载过高!"
fi
sleep 60
done
4.3 逐行读取文件
#!/bin/bash
# 读取服务器列表并逐个检查
while IFS= read -r LINE; do
IP=$(echo "$LINE" | awk '{print $1}')
NAME=$(echo "$LINE" | awk '{print $2}')
echo "检查服务器 $NAME ($IP)..."
ssh -o ConnectTimeout=5 "$IP" uptime 2>/dev/null || echo " 连接失败"
done < server_list.txt
五、函数
#!/bin/bash
# 定义函数
log_message() {
local LEVEL="$1"
local MSG="$2"
local TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] [$LEVEL] $MSG" | tee -a /var/log/myscript.log
}
# 带返回值的函数
check_service() {
local SERVICE="$1"
if systemctl is-active --quiet "$SERVICE"; then
return 0
else
return 1
fi
}
# 调用函数
log_message "INFO" "脚本开始执行"
SERVICES="nginx mysql redis"
for SVC in $SERVICES; do
if check_service "$SVC"; then
log_message "INFO" "$SVC 运行正常"
else
log_message "ERROR" "$SVC 未运行,尝试启动..."
systemctl start "$SVC"
fi
done
log_message "INFO" "脚本执行完毕"
六、数组
#!/bin/bash
# 索引数组
SERVERS=("web01" "web02" "web03" "db01" "db02")
echo "第一个: ${SERVERS[0]}"
echo "全部: ${SERVERS[@]}"
echo "数量: ${#SERVERS[@]}"
# 遍历数组
for SVR in "${SERVERS[@]}"; do
echo "服务器: $SVR"
done
# 关联数组(Bash 4+)
declare -A CONFIG
CONFIG[host]="127.0.0.1"
CONFIG[port]="3306"
CONFIG[user]="root"
CONFIG[db]="myapp"
for KEY in "${!CONFIG[@]}"; do
echo "$KEY = ${CONFIG[$KEY]}"
done
七、实用脚本示例:自动备份
以下是一个完整的自动备份脚本,适合在搬瓦工 VPS 上定时运行:
#!/bin/bash
# VPS 自动备份脚本
set -euo pipefail
BACKUP_DIR="/root/backups"
DATE=$(date '+%Y%m%d_%H%M%S')
KEEP_DAYS=7
LOG_FILE="/var/log/backup.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
mkdir -p "$BACKUP_DIR"
log "开始备份..."
# 备份网站文件
if [ -d "/var/www" ]; then
tar czf "${BACKUP_DIR}/www_${DATE}.tar.gz" /var/www/
log "网站文件备份完成"
fi
# 备份数据库
if command -v mysqldump &>/dev/null; then
mysqldump --all-databases | gzip > "${BACKUP_DIR}/mysql_${DATE}.sql.gz"
log "MySQL 数据库备份完成"
fi
# 备份配置文件
tar czf "${BACKUP_DIR}/config_${DATE}.tar.gz" \
/etc/nginx/ /etc/mysql/ /etc/redis/ 2>/dev/null || true
log "配置文件备份完成"
# 清理旧备份
find "$BACKUP_DIR" -type f -mtime +"$KEEP_DAYS" -delete
log "已清理 ${KEEP_DAYS} 天前的旧备份"
# 统计备份大小
TOTAL_SIZE=$(du -sh "$BACKUP_DIR" | awk '{print $1}')
log "备份完成,总大小: $TOTAL_SIZE"
将脚本添加到 crontab 实现每日自动执行:
crontab -e
# 添加以下行,每天凌晨 3 点执行备份
0 3 * * * /root/scripts/backup.sh
八、调试技巧
# 使用 -x 选项显示每条命令的执行过程
bash -x myscript.sh
# 在脚本中局部开启调试
set -x # 开启
# ... 需要调试的代码 ...
set +x # 关闭
# 使用 trap 捕获错误
trap 'echo "错误发生在第 $LINENO 行"; exit 1' ERR
# 严格模式(推荐在生产脚本中使用)
set -euo pipefail
# -e: 命令失败时立即退出
# -u: 使用未定义变量时报错
# -o pipefail: 管道中任何命令失败则整个管道失败
总结
Bash 脚本编程是 Linux 服务器管理的基础技能。通过本文介绍的变量、条件判断、循环、函数和数组等知识,你可以在搬瓦工 VPS 上编写各种自动化脚本,提升运维效率。建议结合 AWK 与 Sed 文本处理 和 Grep 正则表达式 教程一起学习,掌握更强大的文本处理能力。选购搬瓦工 VPS 请参考全部方案,购买时使用优惠码 NODESEEK2026 可享受 6.77% 的循环折扣。