C 风格判断/循环、并发检测、交互式 select 清单
本文介绍了 Bash 脚本中三种高级编程技巧:C 风格的条件/循环结构、并发任务处理以及交互式 select 菜单。主要内容包括: 条件判断的三种方式:(( )) 处理数值运算、[[ ]] 处理字符串/正则匹配、[ ] 用于 POSIX 兼容场景 C 风格的 for 循环语法 for ((...)),特别适合数值循环和数组索引遍历 并发任务实现方法:后台任务 & 配合 wait 等待,以及
🐚 C 风格判断/循环、并发检测、交互式 select 清单
目标读者:已经掌握基本 if/for/while 的同学
环境建议:#!/usr/bin/env bash+set -euo pipefail(更稳)
1) C 语言风格的条件判断:(( )) 与 [[ ]]
在 Bash 里有三套常见判断语法:
test/[ ]:传统 POSIX,功能基础。[[ ]]:Bash 扩展,字符串/模式匹配强,不受路径名扩展影响。(( )):算术上下文,C 语法手感,0/非 0 逻辑与 C 类似。
1.1 数值判断:(( ))(推荐做整数比较)
#!/usr/bin/env bash
set -euo pipefail
a=10 b=20
if (( a < b )); then # 像 C 一样用 < > == != += -=
echo "a < b"
fi
(( a += 3, b -= 5 )) # 逗号连接多条算术语句
echo "a=$a, b=$b" # a=13, b=15
# 作为条件使用:表达式非 0 为真
(( a - b )) || echo "a == b"
优点:无需 -lt/-gt 等;变量可不加 $;错误更少。
坑点:仅适用于整数;浮点请用 bc 或 awk。
1.2 字符串与模式判断:[[ ]]
file="report_2025.txt"
if [[ $file == report_*\.txt ]]; then # 支持通配符,不会被路径扩展干扰
echo "匹配到报告文件"
fi
s="Hello World"
if [[ $s =~ ^Hello[[:space:]]+World$ ]]; then # 正则匹配(=~)
echo "正则匹配成功"
fi
优点:== 模式匹配、=~ 正则、&&/|| 原生短路。
坑点:=~ 正则右侧不要加引号,否则变成字面量字符串。
1.3 何时用哪种?
- 整数比较 →
(( )) - 字符串/正则/模式 →
[[ ]] - 需要 POSIX 兼容 →
[ ](但功能弱)
2) C 风格 for 循环:for (( init; cond; step ))
Bash 支持 C 语法 for,写数值循环更直观。
#!/usr/bin/env bash
set -euo pipefail
for (( i=0; i<5; i++ )); do
printf "i=%d\n" "$i"
done
# 倒序、步长
for (( i=10; i>=0; i-=2 )); do
echo "$i"
done
2.1 嵌套循环 & 组合判断
for (( i=1; i<=3; i++ )); do
for (( j=1; j<=3; j++ )); do
(( (i+j)%2==0 )) && echo "i=$i j=$j -> 偶数和"
done
done
2.2 与数组搭配(索引循环)
arr=(alpha beta gamma)
for (( i=0; i<${#arr[@]}; i++ )); do
echo "$i: ${arr[i]}"
done
对比:遍历值的方式是 for x in "${arr[@]}"; do ...; done;
索引循环便于配对、并行地访问多个数组。
3) 并发检测:让脚本“多线程思维”
运维/数据脚本里最常见诉求:并发地做一堆检测或请求,加速 N 倍。
Bash 并没有线程,但我们有三把利器:后台任务 (&)、wait 汇总、并发控制。
3.1 最小并发原型:后台 + wait
check_host(){
host="$1"
if ping -c1 -W1 "$host" >/dev/null 2>&1; then
echo "✅ $host 通"
else
echo "❌ $host 不通"
fi
}
hosts=(1.1.1.1 8.8.8.8 192.0.2.99)
for h in "${hosts[@]}"; do
check_host "$h" &
done
wait # 等所有后台任务结束
echo "全部检测完成"
3.2 控制并发度(轻量 semaphore)
用命名管道或作业计数限制并发,例如最多 5 并发:
max_jobs=5
jobcnt=0
for h in "${hosts[@]}"; do
check_host "$h" &
(( ++jobcnt >= max_jobs )) && { wait -n; ((jobcnt--)); } # Bash 5: wait -n 等任一完成
done
wait
若是 Bash 4,可用数组记录 PID,或用
xargs -P、GNU parallel替代。
3.3 xargs 并发(无需写循环)
printf "%s\n" "${hosts[@]}" | xargs -n1 -P4 -I{} bash -c '
h="$1"
if ping -c1 -W1 "$h" >/dev/null 2>&1; then
echo "✅ $h"
else
echo "❌ $h"
fi
' _ {}
-P4:4 并发-n1:每次传 1 个参数-I{}:占位符
3.4 GNU parallel(更强更优雅)
# apt/yum 安装 parallel 后使用
parallel -j 8 'ping -c1 -W1 {} >/dev/null && echo ✅ {} || echo ❌ {}' ::: "${hosts[@]}"
3.5 实战:并发检测 HTTP 健康
check_http(){
url="$1"
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$url" || echo 000)
if (( code>=200 && code<400 )); then
printf "✅ %-30s %s\n" "$url" "$code"
else
printf "❌ %-30s %s\n" "$url" "$code"
fi
}
mapfile -t urls < urls.txt # 每行一个 URL
max=10; cnt=0
for u in "${urls[@]}"; do
check_http "$u" &
(( ++cnt >= max )) && { wait -n; ((cnt--)); }
done
wait
并发三要点:
- 输出乱序?考虑为每个任务缓冲到临时文件,最后统一汇总。
- 接口限流?增加
sleep随机抖动;或用 token bucket 控制节流。 - 错误处理?统计失败计数,全部结束后统一给出汇总与非零退出码。
4) select 清单交互:写个“半图形化”菜单
Bash 自带 select 语法,能快速做命令行菜单。适合跳板、工具集入口、批处理选择场景。
4.1 入门示例
#!/usr/bin/env bash
set -euo pipefail
PS3="请选择要管理的服务(1-3,q退出):"
options=("nginx" "redis" "postgres" "退出")
select opt in "${options[@]}"; do
case "$REPLY" in
1) echo "你选择了 nginx"; break ;;
2) echo "你选择了 redis"; break ;;
3) echo "你选择了 postgres"; break ;;
q|Q|4) echo "再见"; exit 0 ;;
*) echo "非法选择:$REPLY" ;;
esac
done
PS3:提示语select自动打印编号列表;用户输入数字即可- 变量:
$opt为选中项文本,$REPLY为原始输入
4.2 绑定动作的菜单
manage_nginx(){ sudo systemctl "$1" nginx; }
manage_redis(){ sudo systemctl "$1" redis; }
PS3="选择服务:"
services=("nginx" "redis" "退出")
select s in "${services[@]}"; do
case "$s" in
nginx) act=("start" "stop" "restart" "status");;
redis) act=("start" "stop" "restart" "status");;
退出) exit 0 ;;
*) echo "无效"; continue ;;
esac
PS3="选择动作:"
select a in "${act[@]}"; do
case "$a" in
start|stop|restart|status)
"manage_${s}" "$a"; break ;;
*) echo "无效动作" ;;
esac
done
done
进阶建议:
- 配合
dialog/whiptail可做出更好看的 TUI; - 配合配置文件生成菜单(动态扩展服务与动作)。
5) 实战组合:C 风格 + 并发 + select 的“巡检工具”
这个小工具把本文的三块内容糅合起来:
- 用
select选择“主机批量巡检 / URL 健康检查 / 退出”- 用 并发加速检测
- 用
(( ))实现数值逻辑与统计
#!/usr/bin/env bash
set -euo pipefail
PS3="请选择功能:"
menu=("主机存活巡检(ping)" "URL 健康检查(HTTP)" "退出")
select m in "${menu[@]}"; do
case "$REPLY" in
1) # ping 巡检
mapfile -t hosts < hosts.txt
max=8; cnt=0; ok=0; bad=0
check(){
h="$1"
if ping -c1 -W1 "$h" >/dev/null 2>&1; then
echo "✅ $h"
(( ok++ ))
else
echo "❌ $h"
(( bad++ ))
fi
}
for h in "${hosts[@]}"; do
check "$h" &
(( ++cnt >= max )) && { wait -n; ((cnt--)); }
done
wait
echo "统计:OK=$ok, BAD=$bad"
;;
2) # URL 健康
mapfile -t urls < urls.txt
max=10; cnt=0; ok=0; bad=0
check(){
u="$1"
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 "$u" || echo 000)
if (( code>=200 && code<400 )); then
printf "✅ %-40s %s\n" "$u" "$code"
(( ok++ ))
else
printf "❌ %-40s %s\n" "$u" "$code"
(( bad++ ))
fi
}
for u in "${urls[@]}"; do
check "$u" &
(( ++cnt >= max )) && { wait -n; ((cnt--)); }
done
wait
echo "统计:OK=$ok, BAD=$bad"
;;
3|q|Q) echo "再见"; exit 0 ;;
*) echo "无效选择";;
esac
done
6) 踩坑清单(务必收藏)
-
[[ ... ]]中做正则匹配=~时,右侧不要加引号。 -
(( ))只适合整数;浮点用bc或awk。 -
并发时输出可能乱序,需要缓冲到文件或使用有序输出策略。
-
xargs -P与parallel默认不保序,如需保序看其--keep-order/-k选项。 -
大规模并发前先压测目标(端口、接口)承受能力,避免被当作攻击。
-
select的$REPLY是用户输入,不一定合法;别忘了case里兜底分支。 -
全文建议加:
#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t'
7) 一页速记(Cheat Sheet)
-
整数判断:
(( a>b && b>0 )) -
字符串/正则:
[[ $s =~ ^foo|bar$ ]] -
C for:
for((i=0;i<n;i++)); do ...; done -
后台并发:
cmd & ... ; wait -
限速并发(Bash 5):
((++cnt>=N)) && { wait -n; ((cnt--)); } -
xargs 并发:
printf '%s\n' "${arr[@]}" | xargs -n1 -P8 cmd -
select:
PS3="选择:"; select x in A B 退出; do ...; done
更多推荐



所有评论(0)