news 2026/4/19 20:00:24

【Linux 基础知识系列:第二百零一篇】Bash 循环结构进阶:for、while 与 until

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Linux 基础知识系列:第二百零一篇】Bash 循环结构进阶:for、while 与 until

一、简介:为什么循环是 Shell 的“发动机”?

  • Shell 是 Linux 的胶水语言,循环结构负责“重复”——批量处理文件、轮询接口、守护进程、自动重试。

  • 实际场景

    • 一晚备份 500 个数据库 →for循环拼接文件名

    • 等待数据库端口存活 →while循环+sleep

    • 服务异常则一直重启 →until循环探测成功才退出

掌握for / while / until的语法差异与最佳实践,是运维、DevOps、开发者的基本功,也是写“不翻车”脚本的分水岭


二、核心概念:3 种循环一句话记住

循环关键词判断逻辑典型场景
for遍历列表列表耗尽即结束批量文件、固定次数
while条件为真入口判断,真→继续轮询、守护、读取管道
until条件为假入口判断,假→继续等待成功、自动重试

口诀:for 遍历,while 真继续,until 假继续


三、环境准备:3 分钟搞定实验沙箱

  1. 系统
    Ubuntu 20.04+/CentOS 8+/Debian 11+(Bash ≥ 4.3 即可)

  2. 权限
    普通用户可完成 90% 实验;文件系统演示需chmod +x

  3. 实验目录

    mkdir -p ~/bash-loop-lab && cd ~/bash-loop-lab
  4. 确认 Bash

    echo $BASH_VERSION # ≥ 4.3 支持关联数组、关联索引

四、实际案例与步骤:5 大关卡由浅入深

每个脚本均可直接复制,保存后chmod +x xxx.sh && ./xxx.sh跑通。


4.1 for 循环:批量重命名 + 安全前缀

需求:把 200 个.log文件加上日期前缀,防止覆盖。

#!/usr/bin/env bash # file: 01-rename.sh set -euo pipefail date_prefix=$(date +%F) for file in *.log; do [[ -f $file ]] || continue # 空目录保护 new="${date_prefix}_${file}" echo "mv $file $new" mv "$file" "$new" done echo "批量重命名完成"

技巧点

  • for file in *.log避免$(ls *.log)空格裂开的坑。

  • continue跳过目录/空匹配,脚本鲁棒性↑。


4.2 C 风格 for:固定次数倒计时

需求:脚本升级前倒计时 5 秒,可中途取消。

#!/usr/bin/env bash # file: 02-countdown.sh for ((i=5;i>0;i--)); do printf '\r升级将在 %d 秒后开始 ... 按 Ctrl+C 取消' "$i" sleep 1 done printf '\r开始升级! \n'

说明

  • 双括号(())内变量无需$前缀,支持++ -- +=

  • printf \r实现同一行动态刷新,界面友好。


4.3 while 循环:端口未就绪就等待

需求:数据库 3306 端口监听前一直重试,每 2 秒检测一次。

#!/usr/bin/env bash # file: 03-wait-port.sh HOST=127.0.0.1 PORT=3306 TIMEOUT=300 count=0 echo "等待 $HOST:$PORT 就绪 ..." while ! nc -z "$HOST" "$PORT"; do ((count++)) if [[ $count -gt $((TIMEOUT/2)) ]]; then echo "超时退出" >&2; exit 1 fi sleep 2 done echo "端口已就绪,继续执行业务 SQL ..."

依赖

  • nc(nmap-ncat):sudo dnf/apt install -y nc


4.4 until 循环:服务异常则一直重启

需求:Spring Boot jar 异常退出后 5 秒自动重启,直到手动 Ctrl+C。

#!/usr/bin/env bash # file: 04-until-restart.sh JAR=myapp.jar LOG=app.log until java -jar "$JAR" >> "$LOG" 2>&1; do echo "$(date) 服务异常退出,5 秒后重启" >&2 sleep 5 done echo "$(date) 服务正常退出,不再重启"

要点

  • until判断最后一条命令退出码,非 0 就继续循环。

  • 适合“成功即跳出”场景,逻辑比while true更清晰。


4.5 嵌套循环:批量创建目录+文件

需求:生成proj1/{src,doc,test}共 3×3=9 个目录,并在每个目录放 README.md。

#!/usr/bin/env bash # file: 05-nested.sh projects=(proj1 proj2 proj3) folders=(src doc test) for p in "${projects[@]}"; do for f in "${folders[@]}"; do dir="$p/$f" mkdir -p "$dir" echo "# $dir" > "$dir/README.md" done done echo "项目骨架生成完成"

技巧

  • 用数组+双引号避免空格分割;嵌套层级直观。


4.6 循环读取文件:行内空格安全

需求:逐行读取ip.list(格式:IP 端口),检测连通性。

#!/usr/bin/env bash # file: 06-readfile.sh INPUT=ip.list # 方式1:while read 最安全 while IFS= read -r line; do [[ -z "$line" || "$line" == \#* ]] && continue # 跳过空行与注释 ip=${line% *} port=${line#* } if nc -z "$ip" "$port"; then echo "$ip:$port OK" else echo "$ip:$port FAIL" >&2 fi done < "$INPUT"

对比

  • for i in $(cat file)会把行内空格拆成多词 →禁止

  • while read+IFS=保留原始行,100% 安全


4.7 关联数组+for:按分组批量杀进程

需求:按服务名(nginx、php、redis)分组优雅重启。

#!/usr/bin/env bash # file: 07-kill-group.sh declare -A groups=( [web]="nginx php-fpm" [cache]="redis-server" ) for group in "${!groups[@]}"; do echo "=== 重启 $group ===" for proc in ${groups[$group]}; do pkill -USR2 "$proc" # 示例信号,可换 systemctl done done

要求
Bash 4.0+ 支持关联数组;检查版本echo $BASH_VERSION


五、常见问题与解答(FAQ)

问题现象解决
Syntax error: bad for loop variableDash 执行 C 风格for ((;;))指定#!/usr/bin/env bash
ls: cannot access '*.log': No such file or directory空目录展开用 `for file in *.log; do [[ -f $file ]]continue; ...`
死循环 CPU 100%while 内无 sleepsleep 1read -t 1
read 丢失最后一行文件末尾无\n`while read -r line[[ -n $line ]]; do ... done`
变量修改在子 shell 无效管道后while用重定向< fileshopt -s lastpipe

六、实践建议与最佳实践

  1. set -euo pipefail 黄金三件套
    让脚本在变量未定义、管道失败、循环退出码非 0 时立刻失败,避免“静默继续”。

  2. 用数组+双引号代替ls

    files=(*.log) for f in "${files[@]}"; do ...
  3. 循环内打印进度

    printf '\r处理中 %d/%d' "$i" "$total"
  4. 超时退出
    自带计数器或timeout命令,防止死循环。

  5. 调试技巧

    • bash -x script.sh看每次循环变量值。

    • set +x/set -x局部开关,减少刷屏。

  6. 性能优化

    • 大量文件优先find ... -print0 | while IFS= read -r -d '' file; do ...

    • 避免在循环里cat | grep | awk三连,改用 Bash 内置参数替换。


七、总结:一张脑图带走全部要点

Bash 循环 ├─ for:列表遍历 / C 风格计数 ├─ while:条件真继续(轮询) ├─ until:条件假继续(重试) ├─ 嵌套:多级目录、多项目 ├─ read:行内空格安全 └─ 黄金习惯:引号 + -euo pipefail + 超时

掌握for / while / until语法差异、安全写法、调试技巧,你就拥有了:

  • 批量自动化的瑞士军刀:文件改名、备份、部署脚本 10 行搞定。

  • 服务守护的坚固盾牌:端口等待、异常重启、日志监控不再手写死循环。

  • 跨平台兼容的移植指南:避开$(ls)for i in $(cat file)等经典陷阱。

立刻打开终端,把本文脚本复制到~/bash-loop-lab,跑一遍、改一遍、拆一遍,写属于自己的第一个健壮循环!祝你玩得开心,循环永不死。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 4:05:16

速藏!AI大模型学习指南:从新手入门到实战通关

当AI大模型能自动生成技术方案、辅助调试代码&#xff0c;甚至独立开发简单应用时&#xff0c;它已不再是技术圈的“奢侈品”&#xff0c;而是每个程序员、IT从业者的“必备技能包”。无论是想转行AI的职场人、刚接触编程的小白&#xff0c;还是寻求技术突破的开发者&#xff0…

作者头像 李华
网站建设 2026/4/17 22:58:15

攻防世界——心仪的公司

拿到数据包先尝试用关键字搜索flag 只找到一个非正常格式的flag 尝试依据数据包名称来搜索关键字&#xff08;webshell&#xff09; 发现都指向webshell.jpg这个文件 并且由第二张图的路径和文件名可知是用web中的http协议进行传输 精准查询webshell文件 http.file_data co…

作者头像 李华
网站建设 2026/4/18 8:46:30

种子扩散预览:兼具快速推理和高性能的下一代代码生成模型

概述 本研究提出了基于离散状态扩散&#xff08;DSD&#xff09;的快速推理模型–种子扩散预览&#xff08;Seed Diffusion Preview&#xff09;&#xff0c;作为大规模语言建模的一种新方法。 传统的自回归&#xff08;AR&#xff09;模型是按顺序生成标记的&#xff0c;这限制…

作者头像 李华
网站建设 2026/4/17 14:41:27

多路召回(Multi-Route Retrieval)

核心原理与技术架构多路召回通过并行执行多个检索策略&#xff0c;覆盖不同语义维度&#xff08;关键词、语义、多模态等&#xff09;&#xff0c;再通过融合算法&#xff08;如 RRF、加权排名&#xff09;生成最终结果&#xff0c;解决单一检索的 “漏检” 和 “错配” 问题。…

作者头像 李华