暗色模式

Bash 脚本编程:从变量与位置参数到循环函数与调试

技术教程
2026-08-22
11
0

Bash 脚本编程:从变量与位置参数到循环函数与调试

本文要点
  • 脚本骨架:以 #!/usr/bin/env bash 开头声明解释器,赋执行权限后即可直接运行。
  • 变量与位置参数$0 $1 $# $@ 分别表示脚本名、第 n 个参数、参数个数与全部参数。
  • 条件判断if / elif / else 配合 [ ] 测试表达式做分支处理。
  • 循环forwhile 结合 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 两个参数,位置参数立刻体现出来:

bash 变量与位置参数演示

图中可以看到 $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 信息、三个脚本文件的大小,以及数值比较结果,全部符合预期:

bash 条件判断与 for 循环演示

如果需要指定次数或按条件循环,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 返回成功/失败状态,调用方用 $? 取回。这是一个经典的服务状态巡检函数,传入服务名就能判断它是否在运行:

bash 函数与退出码演示

图上 ssh 返回「运行中」、nginx 返回「未运行」,最后一行的 docker 检查结果为 0 说明 docker 服务处于 active 状态。用这种方式写巡检脚本,输出一眼就能看清哪些服务异常。

调试:bash -x

脚本报错或逻辑不对时,bash -x 脚本名 会逐行打印每一条实际执行的命令(行首带 +),并显示变量展开后的结果,是排查脚本问题的第一利器:

bash -x demo1.sh web

bash -x 调试跟踪演示

从图中能清楚看到每个 echo 前的 + 行都展示了变量替换后的完整命令,例如 + echo '参数总数:1'。对照「+ 行」与「输出行」,就能定位是变量赋值错了、还是判断条件写错。更规范的做法是在脚本开头加 set -euxo pipefail-e 出错即停、-u 杜绝未定义变量、-x 打印跟踪,上线前去掉 -x 即可。

小结

Bash 脚本入门记住这条主线即可:shebang 声明解释器 → 变量与位置参数 → if 条件分支 → for/while 循环 → 函数封装 → bash -x 调试。实战中把这几个点串起来,就能写出像服务巡检、日志清理、定时备份这一类自动化脚本。推荐的进阶资料有 GNU Bash 参考手册Bash Guide,前者是官方权威文档,后者有不少易踩的坑的详细解释。

发表评论

暂无评论,快来抢沙发吧!