文章目录
-
- 一、脚本基础结构
-
- 1. 解释器声明(Shebang)
- 2. 注释语法
- 3. 执行方式
- 二、变量与数据类型
-
- 1. 变量定义与使用
- 2. 特殊变量
- 3. 只读变量与删除变量
- 4. 数值运算
- 5. 字符串操作
- 三、输入与输出
-
- 1. 输出(echo)
- 2. 输入(read)
- 3. 重定向
- 四、条件判断(if语句)
-
- 基本语法
- 常用判断条件
- 实战示例:检查Nginx服务
- 五、循环语句
-
- 1. for循环
- 2. while循环
- 3. until循环(条件为假时执行)
- 六、case分支语句
- 七、函数
- 八、错误处理与调试
-
- 1. 错误中断
- 2. 调试模式
- 3. 检查命令执行结果
- 九、实战案例:日志清理脚本
- 十、新手避坑指南
- 总结
一、脚本基础结构
1. 解释器声明(Shebang)
脚本首行必须指定解释器,告诉系统用哪个程序执行:
#!/bin/bash # 最常用,指定Bash解释器
#!/usr/bin/env bash # 跨平台兼容写法(推荐)
#!/bin/sh # POSIX标准Shell(部分系统sh是bash的简化版)
2. 注释语法
# 单行注释
: <<'EOF'
多行注释
可以写很多行
EOF
3. 执行方式
# 方式1:赋予执行权限后运行(推荐)
chmod +x script.sh
./script.sh
# 方式2:指定解释器运行(无需权限)
bash script.sh
sh script.sh
二、变量与数据类型
1. 变量定义与使用
# 定义变量(等号两侧绝对不能有空格!)
name="Alice"
port=8080
path="/var/log"
# 使用变量
echo $name # 基本用法
echo ${name}_backup # 推荐:用{}明确变量边界,避免歧义
echo "$name" # 双引号内会解析变量
echo '$name' # 单引号内原样输出,不解析
2. 特殊变量
$0 # 脚本文件名
$1 $2 # 第1、第2个位置参数
$# # 参数个数
$* # 所有参数(作为一个整体字符串)
$@ # 所有参数(每个参数独立,推荐用于循环)
$? # 上一条命令的返回码(0=成功,非0=失败)
$$ # 当前进程PID
$USER # 当前登录用户
$PWD # 当前工作目录
3. 只读变量与删除变量
readonly PI=3.14 # 只读,不可修改
unset name # 删除变量
4. 数值运算
a=10
b=3
# 方法1:$(()) 推荐
echo $((a + b)) # 13
echo $((a * b)) # 30
echo $((a % b)) # 1
# 方法2:expr(注意空格)
echo $(expr $a – $b) # 7
# 方法3:bc(支持浮点数)
echo "scale=2; 10 / 3" | bc # 3.33
5. 字符串操作
str="Hello World"
echo ${#str} # 字符串长度:11
echo ${str:0:5} # 截取:Hello
echo ${str/World/Bash} # 替换:Hello Bash
三、输入与输出
1. 输出(echo)
echo "普通输出"
echo -e "换行\\n测试" # -e 支持转义符
echo "不换行" | tr -d '\\n'
echo "错误信息" >&2 # 输出到标准错误流
2. 输入(read)
read -p "请输入用户名:" username # 带提示
read -t 10 -p "请输入密码:" password # 10秒超时
read -s -p "密码:" pwd # -s 隐藏输入
3. 重定向
echo "内容" > file.log # 覆盖写入
echo "追加" >> file.log # 追加写入
./script.sh > out.log 2>&1 # 标准输出+错误输出都写入文件
四、条件判断(if语句)
基本语法
if [ 条件 ]; then
命令
elif [ 条件2 ]; then
命令
else
命令
fi
常用判断条件
# 文件判断
[ -f "$file" ] # 文件存在且是普通文件
[ -d "$dir" ] # 目录存在
[ -e "$path" ] # 路径存在(不区分类型)
[ -r "$file" ] # 可读
[ -w "$file" ] # 可写
[ -x "$file" ] # 可执行
[ -s "$file" ] # 文件非空
# 字符串判断
[ -z "$str" ] # 字符串为空
[ -n "$str" ] # 字符串非空
[ "$a" = "$b" ] # 字符串相等
[ "$a" != "$b" ] # 字符串不等
# 数值比较
[ $a -eq $b ] # 等于
[ $a -ne $b ] # 不等于
[ $a -gt $b ] # 大于
[ $a -lt $b ] # 小于
[ $a -ge $b ] # 大于等于
[ $a -le $b ] # 小于等于
实战示例:检查Nginx服务
if ps -ef | grep -v grep | grep -q nginx; then
echo "Nginx正在运行"
else
echo "Nginx未运行,正在重启…"
systemctl restart nginx
fi
五、循环语句
1. for循环
# 遍历列表
for i in 1 2 3 4 5; do
echo "数字:$i"
done
# 范围遍历
for i in {1..10}; do
echo "第 $i 次"
done
# C语言风格
for ((i=0; i<10; i++)); do
echo $i
done
# 遍历文件
for file in /var/log/*.log; do
echo "处理文件:$file"
done
2. while循环
count=0
while [ $count -lt 5 ]; do
echo "当前值:$count"
count=$((count + 1))
done
# 逐行读取文件
while IFS= read -r line; do
echo "行内容:$line"
done < file.txt
3. until循环(条件为假时执行)
count=0
until [ $count -ge 5 ]; do
echo $count
count=$((count + 1))
done
六、case分支语句
适用于多值匹配,替代多个if-elif:
case $1 in
start)
echo "启动服务…"
systemctl start nginx
;;
stop)
echo "停止服务…"
systemctl stop nginx
;;
restart)
echo "重启服务…"
systemctl restart nginx
;;
*)
echo "用法:$0 {start|stop|restart}"
exit 1
;;
esac
七、函数
# 定义函数
check_service() {
local service_name=$1 # local 局部变量
if systemctl is-active –quiet "$service_name"; then
echo "$service_name 正在运行"
return 0
else
echo "$service_name 未运行"
return 1
fi
}
# 调用函数
check_service nginx
result=$? # 获取函数返回值
echo "返回码:$result"
八、错误处理与调试
1. 错误中断
set -e # 任何命令失败立即退出脚本
set -u # 使用未定义变量时报错
set -o pipefail # 管道中任一命令失败则整体失败
2. 调试模式
# 运行时调试
bash -x script.sh
# 脚本内开启/关闭调试
set -x # 开启:显示每条执行的命令
set +x # 关闭调试
3. 检查命令执行结果
if ! command -v nginx &>/dev/null; then
echo "nginx未安装"
exit 1
fi
九、实战案例:日志清理脚本
#!/usr/bin/env bash
set -euo pipefail
# 配置
LOG_DIR="/var/log/app"
KEEP_DAYS=30
BACKUP_DIR="/backup/logs"
# 函数:清理过期日志
clean_logs() {
local dir=$1
local days=$2
if [ ! -d "$dir" ]; then
echo "目录不存在:$dir"
return 1
fi
echo "清理 $dir 中超过 ${days} 天的日志…"
find "$dir" -name "*.log" -mtime +$days -delete
echo "清理完成"
}
# 主逻辑
echo "===== 日志清理开始:$(date) ====="
clean_logs "$LOG_DIR" "$KEEP_DAYS"
# 备份今日日志
mkdir -p "$BACKUP_DIR"
tar -czf "${BACKUP_DIR}/logs_$(date +%Y%m%d).tar.gz" "$LOG_DIR"/*.log 2>/dev/null || true
echo "===== 清理结束:$(date) ====="
十、新手避坑指南
| name = "value" | name="value" | 等号两侧不能有空格 |
| if [$a -eq $b] | if [ $a -eq $b ] | [ 和 ] 内侧必须有空格 |
| echo $var_text | echo ${var}_text | 用{}明确变量边界 |
| 忘记加执行权限 | chmod +x script.sh | 否则./script.sh报权限错误 |
| 不检查返回值 | `cmd | |
| 硬编码路径 | 使用变量 | 便于维护和跨环境部署 |
总结
Shell脚本的核心语法可以归纳为:变量 → 条件 → 循环 → 函数 → 错误处理。掌握这些基础模块,你就能构建出绝大多数自动化运维脚本。建议从简单的文件操作、服务检查脚本开始练习,逐步过渡到复杂的批量部署和监控告警场景。
💡 学习建议:多用bash -x调试,多写set -euo pipefail保底,养成检查$?的习惯,你的脚本会越来越健壮!




