Bash 脚本编程:从变量与位置参数到循环函数与调试
本文要点
- 脚本骨架:以
#!/usr/bin/env bash开头声明解释器,赋执行权限后即可直接运行。 - 变量与位置参数:
$0$1$#$@分别表示脚本名、第 n 个参数、参数个数与全部参数。 - 条件判断:
if/elif/else配合[ ]测试表达式做分支处理。 - 循环:
for、while结合break/continue可批量处理文件与服务巡检。 - 函数与调试:函数封装复用逻辑并用
return返回状态,bash -x逐行跟踪脚本执行。
写自动化脚本是 Linux 运维进阶的必备技能:重复性的备份、巡检、批量配置都能用一段 Bash 脚本搞定。本文从零开始,以 Ubuntu 24.04 上的真实运行示例,讲透脚本的变量、位置参数、条件判断、循环、函数与调试方法。文中的所有代码都在 demo 服务器上实际执行过,截图即真实输出。
脚本的基本骨架
一个可执行的 Bash 脚本通常长这样:
#!/usr/bin/env bash
# demo1.sh:变量与位置参数示例
site="blog.astarry.cn"
user="root"
echo "站点: ${site}"
echo "当前用户: ${user}"第一行 #!(shebang)告诉系统用哪个解释器运行本文件,/usr/bin/env bash 会自动定位 bash 路径,比写死路径更通用。脚本内容可以先用 bash 脚本名 方式直接运行(无需执行权限),也可以 chmod +x 赋予权限后通过 ./脚本名 运行:
chmod +x demo1.sh
./demo1.sh # 等价于 bash demo1.sh变量与位置参数
脚本中 site="blog.astarry.cn" 这种写法就是定义变量,引用时用 $site 或 ${site}。花括号更长但更安全,能避免 $site_后缀 这类歧义。
运维脚本经常需要「带参运行」,位置参数就是命令行传入的值:
| 写法 | 含义 |
|---|---|
$0 | 脚本自身名称 |
$1 / $2 | 第 1 / 第 2 个位置参数 |
$# | 位置参数的总个数 |
$@ | 所有位置参数 |
$? | 上一条命令的退出码(0 表示成功) |
下面这个脚本把站点、用户、参数信息一起打印出来:
#!/usr/bin/env bash
site="blog.astarry.cn"
user="root"
echo "站点: ${site}"
echo "当前用户: ${user}"
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "参数总数: $#"
echo "所有参数: $@"在服务器上实际运行,传 web prod 两个参数,位置参数立刻体现出来:

图中可以看到 $1 取到 web,$# 为 2,$@ 输出了 web prod 全部参数。写配置类脚本时常用这个特性:bash deploy.sh stage 8080 里 $1=stage、$2=8080。
条件判断:if 分支
真实脚本很少直来直去,大多要根据状态走不同分支。if 配合 [ 条件 ] 测试表达式完成判断:
n=12
if [ "$n" -gt 10 ]; then
echo "$n 大于 10"
elif [ "$n" -eq 10 ]; then
echo "$n 等于 10"
else
echo "$n 小于 10"
fi-gt 大于、-eq 等于、-lt 小于分别对应数字比较;文件判断常用的有 -f(普通文件)、-d(目录)、-s(非空文件)。注意 [ 和 ] 两侧必须留空格,条件表达式加双引号防止空值报错。上面这段判断 12 大于 10 正是下图输出的最后一行。
for 循环批量处理
批量操作是脚本最高价值的地方。for 变量 in 列表 会遍历每一项执行循环体,配合文件判断可以跳过不存在的项:
for f in /root/bash-demo/*.sh; do
[ -f "$f" ] || continue
echo "$(basename "$f") 大小: $(stat -c %s "$f") 字节"
done[ -f "$f" ] || continue 表示文件不存在就跳过本次循环;$(basename "$f") 是命令替换,执行外部命令并取回结果。把条件判断与 for 循环组合起来,一次处理整个目录的文件:
#!/usr/bin/env bash
if [ -f /etc/os-release ]; then
echo "/etc/os-release 存在,当前系统信息:"
head -1 /etc/os-release
fi
echo "--- 遍历 bash-demo 目录的 .sh 文件 ---"
for f in /root/bash-demo/*.sh; do
[ -f "$f" ] || continue
echo "$(basename "$f") 大小: $(stat -c %s "$f") 字节"
done
echo "--- 数值比较 ---"
n=12
if [ "$n" -gt 10 ]; then
echo "$n 大于 10"
elif [ "$n" -eq 10 ]; then
echo "$n 等于 10"
else
echo "$n 小于 10"
fi真实运行输出了 Ubuntu 24.04 系统的 os-release 信息、三个脚本文件的大小,以及数值比较结果,全部符合预期:

如果需要指定次数或按条件循环,while 更合适:while [ 条件 ]; do ... done。做监控脚本时经常用 while true 加 sleep 实现定时轮询。
函数与退出码
脚本长了之后,把重复逻辑封装成函数,用 函数名() 定义、直接调用:
check_service() {
local svc=$1
if systemctl is-active --quiet "$svc" 2>/dev/null; then
echo "$svc: 运行中"
return 0
else
echo "$svc: 未运行"
return 1
fi
}
for s in ssh nginx systemd-timesyncd; do
check_service "$s"
done
echo "函数退出码示例:"
check_service docker >/dev/null
echo "docker 检查结果为 $?"local svc 把变量限定在函数内部避免污染全局;return 0 / return 1 返回成功/失败状态,调用方用 $? 取回。这是一个经典的服务状态巡检函数,传入服务名就能判断它是否在运行:

图上 ssh 返回「运行中」、nginx 返回「未运行」,最后一行的 docker 检查结果为 0 说明 docker 服务处于 active 状态。用这种方式写巡检脚本,输出一眼就能看清哪些服务异常。
调试:bash -x
脚本报错或逻辑不对时,bash -x 脚本名 会逐行打印每一条实际执行的命令(行首带 +),并显示变量展开后的结果,是排查脚本问题的第一利器:
bash -x demo1.sh web
从图中能清楚看到每个 echo 前的 + 行都展示了变量替换后的完整命令,例如 + echo '参数总数:1'。对照「+ 行」与「输出行」,就能定位是变量赋值错了、还是判断条件写错。更规范的做法是在脚本开头加 set -euxo pipefail:-e 出错即停、-u 杜绝未定义变量、-x 打印跟踪,上线前去掉 -x 即可。
小结
Bash 脚本入门记住这条主线即可:shebang 声明解释器 → 变量与位置参数 → if 条件分支 → for/while 循环 → 函数封装 → bash -x 调试。实战中把这几个点串起来,就能写出像服务巡检、日志清理、定时备份这一类自动化脚本。推荐的进阶资料有 GNU Bash 参考手册 和 Bash Guide,前者是官方权威文档,后者有不少易踩的坑的详细解释。
评论 (0)
暂无评论,快来抢沙发吧!