十、Linux Shell脚本:流程控制语句

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
应用实时监控服务-应用监控,每月50GB免费额度
函数计算FC,每月15万CU 3个月
简介: 要让脚本从简单的“指令清单”升级为能干的“小助手”,就需要用if教它根据条件做判断,用for和while循环让它重复处理任务,再用case语句帮它在多个选项中做出清晰的选择
在掌握了Shell脚本的 变量与运算之后, 流程控制构建复杂和实用脚本关键。它 允许脚本根据 不同的条件选择执行路径,或 重复执行特定任务,从而 实现脚本灵活性与自动化

## 思维导图
image.png
image.png
image.png


## 一、条件判断
if 语句是 最基本条件控制结构,它 评估一个命令退出状态码 (exit code)。如果 退出码为 0 (成功),则 条件为真;如果为 非 0 (失败),则 条件为假

### if 的基本结构
格式:
bash if [ 条件判断 ]; then # 条件为真时执行的代码块 fi
代码示例:检查文件是否存在
bash #!/bin/bash TARGET_FILE="/etc/hosts" if [ -f "$TARGET_FILE" ]; then echo "文件 '$TARGET_FILE' 存在。" fi

### if...else 结构
格式:
bash if [ 条件判断 ]; then # 条件为真时执行的代码块 else # 条件为假时执行的代码块 fi
代码示例:判断目录是否存在
bash #!/bin/bash TARGET_DIR="/var/log/non_existent_dir" if [ -d "$TARGET_DIR" ]; then echo "目录 '$TARGET_DIR' 存在。" else echo "目录 '$TARGET_DIR' 不存在,将尝试创建。" mkdir -p "$TARGET_DIR" fi

### if...elif...else 结构
格式:
bash if [ 条件1 ]; then # 条件1为真时执行 elif [ 条件2 ]; then # 条件1为假,但条件2为真时执行 else # 以上所有条件都为假时执行 fi
代码示例:根据HTTP状态码判断响应
bash #!/bin/bash HTTP_CODE=200 if [ $HTTP_CODE -eq 200 ]; then echo "请求成功 (OK)" elif [ $HTTP_CODE -eq 404 ]; then echo "资源未找到 (Not Found)" elif [ $HTTP_CODE -eq 500 ]; then echo "服务器内部错误 (Internal Server Error)" else echo "收到未知的HTTP状态码: $HTTP_CODE" fi

### 条件判断的实现:test 和 [ ]
在Shell中, if 后的条件通常由 test 命令或其等价形式 [ ... ] 来实现。 [[ ... ]][ ... ]扩展版本,提供了 更多功能 (如模式匹配、逻辑与/或)。

常见判断类型:
> 文件测试: -f (是普通文件?), -d (是目录?), -e (存在?), -s (大小非0?), -r (可读?), -w (可写?), -x (可执行?)
字符串比较: "$str1" = "$str2", "$str1" != "$str2", -z "$str" (字符串为空?), -n "$str" (字符串非空?)
整数比较: -eq (等于), -ne (不等于), -gt (大于), -ge (大于等于), -lt (小于), -le (小于等于)

## 二、循环结构
循环用于 重复执行一段代码,直到 满足某个退出条件。

### for 循环
for 循环擅长 遍历一个列表 (字符串、文件名、数字序列等) 或进行 C语言风格数值循环

格式 (遍历列表):
bash for variable_name in item1 item2 item3 ...; do # 循环体 done
代码示例 (遍历并重命名文件):
bash #!/bin/bash # 将所有 .txt 文件重命名为 .txt.bak for filename in *.txt; do if [ -f "$filename" ]; then echo "正在备份: $filename -> ${filename}.bak" mv "$filename" "${filename}.bak" fi done

格式 (C风格数值循环):
bash for (( initialization; condition; step )); do # 循环体 done
代码示例 (执行三次ping测试):
bash #!/bin/bash TARGET_HOST="8.8.8.8" for (( i=1; i<=3; i++ )); do echo "--- 第 $i 次 PING 测试 ---" ping -c 1 "$TARGET_HOST" done

### while 循环
while 循环在 每次迭代前检查条件,只要 条件为真,就 继续执行循环体。

格式:
bash while [ 条件判断 ]; do # 循环体 done
代码示例:逐行读取文件
bash #!/bin/bash CONFIG_FILE="/etc/fstab" while read -r line; do # 忽略注释和空行 if [[ "$line" =~ ^# || -z "$line" ]]; then continue fi echo "读取到配置行: $line" done < "$CONFIG_FILE"

### until 循环
until 循环与 while 逻辑相反:只要 条件为假,就 继续执行循环体,直到 条件变为真才停止。

格式:
bash until [ 条件判断 ]; do # 循环体 done
代码示例:等待服务端口启动
bash #!/bin/bash PORT=8080 TIMEOUT=10 COUNT=0 until nc -z localhost $PORT >/dev/null 2>&1; do if [ $COUNT -ge $TIMEOUT ]; then echo "等待端口 $PORT 超时!" exit 1 fi echo "端口 $PORT 尚未启动,等待1秒..." sleep 1 COUNT=$((COUNT + 1)) done echo "端口 $PORT 已成功启动!"

### 循环控制:break 和 continue
break: 立即当前循环中完全跳出 continue: 跳过当前循环的 剩余部分,直接 开始下一次迭代。

代码示例:在循环中处理文件
bash #!/bin/bash for file in /var/log/*; do if [ -d "$file" ]; then continue # 如果是目录,则跳过 fi echo "正在处理文件: $file" if [ -s "$file" ] && grep -q "ERROR" "$file"; then echo "在文件 '$file' 中找到错误,停止处理。" break # 找到错误后,完全停止 fi done

## 三、分支选择
case 语句提供了一种 更清晰的方式来 处理多重条件分支,是 if...elif...else一种替代方案,特别适合 基于单个变量值进行匹配

格式:
bash case $variable in pattern1) # 匹配 pattern1 时执行 ;; pattern2|pattern3) # 匹配 pattern2 或 pattern3 时执行 ;; *) # 默认情况,当以上模式都不匹配时执行 ;; esac
代码示例:脚本参数解析
bash #!/bin/bash ACTION=$1 case $ACTION in start) echo "正在启动服务..." # systemctl start my_service ;; stop) echo "正在停止服务..." # systemctl stop my_service ;; status) echo "检查服务状态..." # systemctl status my_service ;; *) echo "用法: $0 {start|stop|status}" exit 1 ;; esac

---
## 练习题

题目:

  1. 文件权限检查:写一个脚本,接收一个文件名作为参数 ($1)。脚本需要判断当前用户对该文件是否同时拥有读、写、执行权限。如果同时拥有,打印 "Full permissions granted";否则打印 "Permissions incomplete"。
  2. 字符串与逻辑判断:写一个脚本,检查变量 ENVIRONMENT 的值。如果值是 production 并且 变量 FORCE_DEPLOY 的值不是 true,则打印 "Safety check passed: Not a forced production deploy." 并退出;否则,打印 "Proceeding with deployment."。
  3. C风格 for 循环与算术:使用C风格的 for 循环,打印出从10到20之间所有的偶数 (包括10和20)。
  4. for 循环与通配符:写一个脚本,查找 /var/log 目录下所有以 .log 结尾的非空文件,并打印出它们的文件名。
  5. while 循环读取标准输入:写一个脚本,持续读取用户从键盘输入的内容,直到用户输入 quit 为止。对于quit 的输入,脚本应该将其回显到屏幕上。
  6. until 循环与命令退出码grep 命令在找到匹配项时退出码为0,找不到时为1。写一个 until 循环,每隔2秒检查一次系统日志 (/var/log/messagesjournalctl -f 的输出,为简化可检查一个普通文件) 是否出现了 "critical error" 字符串,一旦出现就打印 "Critical error detected!" 并退出。
  7. 嵌套循环与 break n:写一个嵌套循环。外层循环从1到3,内层循环从1到3。在内层循环中,如果内外两个循环变量 (ij) 相等,则同时跳出内外两层循环。每次循环都打印当前的 ij 的值。
  8. case 语句与通配符:写一个 case 语句,判断一个文件名变量 FILENAME文件类型。如果文件名以 .log 结尾,打印 "Log file";如果以 .tar.gz.tgz 结尾,打印 "Compressed archive";如果以 .sh 结尾,打印 "Shell script";其他情况打印 "Unknown file type"。
  9. select 菜单 (高级)select 是一个特殊的循环结构,用于创建交互式菜单。写一个脚本,使用 select 让用户从 "Start", "Stop", "Restart", "Exit" 四个选项中选择一个操作,并根据用户的选择打印相应的信息。当用户选择 "Exit" 时,脚本退出。
答案与解析:
  1. 文件权限检查:
    ```bash

    !/bin/bash

    if [ -z "$1" ]; then
    echo "用法: $0 <文件名>"
    exit 1
    fi

if [ -r "$1" ] && [ -w "$1" ] && [ -x "$1" ]; then
echo "Full permissions granted"
else
echo "Permissions incomplete"
fi

   *   **解析:** `if` 语句中的 `-r`, `-w`, `-x` 是文件测试操作符,分别检查读、写、执行权限。`&&` 是逻辑与操作符,要求<font color="teal">所有条件都为真</font>才执行 `then` 块。

2.  **字符串与逻辑判断:**
```bash
#!/bin/bash
ENVIRONMENT="production"
FORCE_DEPLOY="false"

if [[ "$ENVIRONMENT" == "production" && "$FORCE_DEPLOY" != "true" ]]; then
  echo "Safety check passed: Not a forced production deploy."
  exit 0
else
  echo "Proceeding with deployment."
fi
  • 解析: 使用了 [[ ... ]] 扩展测试,它内部支持 && (逻辑与) 和 != (字符串不等于) 操作符,语法更自然
  1. C风格 for 循环与算术:

    #!/bin/bash
    for (( num=10; num<=20; num+=2 )); do
    echo $num
    done
    
    • 解析: C风格的 for 循环通过初始化 num=10条件 num<=20,以及步进 num+=2 来精确控制循环,直接打印出范围内的偶数。
  2. for 循环与通配符:

    #!/bin/bash
    for logfile in /var/log/*.log; do
    if [ -s "$logfile" ]; then
    echo "找到非空日志文件: $(basename "$logfile")"
    fi
    done
    
    • 解析: *.log 是一个通配符for 循环会遍历所有匹配的文件名。-s 文件测试操作符用于判断文件大小是否大于零basename 命令用于提取文件名,去除路径。
  3. while 循环读取标准输入:

    #!/bin/bash
    echo "请输入内容 (输入 'quit' 退出):"
    while read -r input_line; do
    if [ "$input_line" == "quit" ]; then
    break
    fi
    echo "你输入了: $input_line"
    done
    
    • 解析: while read -r input_line读取标准输入标准模式。循环会一直持续,直到 read 命令失败 (例如,用户按下Ctrl+D) 或遇到 break
  4. until 循环与命令退出码:
    ```bash

    !/bin/bash

    LOG_FILE_TO_CHECK="my_app.log"
    touch $LOG_FILE_TO_CHECK # 创建一个空文件用于测试

echo "正在监控 '$LOG_FILE_TO_CHECK' ..."

在另一个终端执行 echo "critical error" >> my_app.log 来触发

until grep -q "critical error" "$LOG_FILE_TO_CHECK"; do
sleep 2
done

echo "Critical error detected!"

   *   **解析:** `until` 循环的<font color="darkslategray">条件是命令本身</font> (`grep -q ...`)。只要 `grep` <font color="indigo">找不到</font>字符串 (退出码非0,条件为假),循环就<font color="blue">继续</font>。一旦<font color="red">找到</font> (退出码为0,条件为真),循环<font color="green">终止</font>。

7.  **嵌套循环与 `break n`:**
```bash
#!/bin/bash
for (( i=1; i<=3; i++ )); do
  echo "外层循环: i=$i"
  for (( j=1; j<=3; j++ )); do
    echo "  内层循环: j=$j"
    if [ $i -eq $j ]; then
      echo "  i 等于 j,跳出所有循环!"
      break 2 # '2' 表示跳出两层循环
    fi
  done
done
  • 解析: break n 命令可以跳出指定层数的循环。break 1 (或 break) 只跳出当前层,break 2 跳出当前层和其外一层。
  1. case 语句与通配符:
    ```bash

    !/bin/bash

    FILENAME="archive-2023.tar.gz"

case $FILENAME in
.log)
echo "Log file"
;;
.tar.gz|.tgz)
echo "Compressed archive"
;;
.sh)
echo "Shell script"
;;
*)
echo "Unknown file type"
;;
esac

   *   **解析:** `case` 语句的模式<font color="purple">支持通配符</font>,如 `*` (匹配任意字符序列)。`|` 用于<font color="teal">分隔多个模式</font>,表示“或”。

9.  **`select` 菜单:**
```bash
#!/bin/bash
PS3="请选择一个操作 (输入数字): "
options=("Start" "Stop" "Restart" "Exit")

select opt in "${options[@]}"; do
  case $opt in
    "Start")
      echo "正在启动..."
      ;;
    "Stop")
      echo "正在停止..."
      ;;
    "Restart")
      echo "正在重启..."
      ;;
    "Exit")
      echo "退出脚本。"
      break
      ;;
    *)
      echo "无效选项 '$REPLY',请重新选择。"
      ;;
  esac
done
  • 解析: select自动生成一个带编号的菜单。用户的输入编号被翻译对应的选项值 (赋给变量opt),而原始输入则保存在 $REPLY 中。
目录
相关文章
|
2月前
|
存储 安全 Unix
七、Linux Shell 与脚本基础
别再一遍遍地敲重复的命令了,把它们写进Shell脚本,就能一键搞定。脚本本质上就是个存着一堆命令的文本文件,但要让它“活”起来,有几个关键点:文件开头最好用#!/usr/bin/env bash来指定解释器,并用chmod +x给它执行权限。执行时也有讲究:./script.sh是在一个新“房间”(子Shell)里跑,不影响你;而source script.sh是在当前“房间”里跑,适合用来加载环境变量和配置文件。
353 9
|
2月前
|
安全 Linux Shell
四、Linux核心工具:Vim, 文件链接与SSH
要想在Linux世界里游刃有余,光会“走路”还不够,还得配上几样“高级装备”。首先是Vim编辑器,它像一把瑞士军刀,让你能在命令行里高效地修改文件。然后要懂“软硬链接”,软链接像个快捷方式,硬链接则是给文件起了个别名。最后,SSH是你的“传送门”,不仅能让你安全地远程登录服务器,还能用scp轻松传输文件,设置好密钥更能实现免-密登录,极大提升效率。
304 3
|
2月前
|
消息中间件 人工智能 运维
事件驱动重塑 AI 数据链路:阿里云 EventBridge 发布 AI ETL 新范式
“一个简单的数据集成任务,开始时总是轻松愉快的,但随着业务扩展,数据源越来越多,格式越来越乱,整个数据链路就会变得一团糟。”陈涛在演讲中指出了当前 AI 数据处理的普遍困境。扩展难、运维难、稳定性差,这三大挑战已成为制约 AI 应用创新和落地的关键瓶颈。针对这些痛点,在2025云栖大会期间,阿里云重磅发布了事件驱动 AI ETL 新范式,其核心产品 EventBridge 通过深度集成 AI 能力,为开发者提供了一套革命性的解决方案,旨在彻底改变 AI 时代的数据准备与处理方式。
298 21
|
2月前
|
存储 安全 Linux
三、Linux用户与权限管理详解
管理Linux系统就像当一个大楼的管家。首先,你得用useradd和passwd给新员工发“钥匙”(创建用户并设密码),并用groupadd把他们分到不同“部门”(用户组)。然后,你要为每个“房间”(文件或目录)设定规矩,这就是文件权限:用chmod命令设置谁(所有者、同部门、其他人)可以“进入”(x)、“读取”(r)或“写入”(w)。最后,用chown还能把房间的归属权转让给别人。
368 3
|
2月前
|
缓存 安全 Linux
六、Linux核心服务与包管理
在没有网络的情况下,使用系统安装光盘是获取RPM包的常用方法。场景二:配置本地文件镜像源 (使用系统安装光盘/ISO)(检查RPM包的GPG签名以保证安全) 或。YUM/DNF包管理工具 (yum/dnf)(此处可以放置您为本主题制作的思维导图)处理依赖问题的危险选项 (应极力避免)(覆盖文件、替换已安装包)。(list) 则是列出文件。(query file) 是。(假设系统安装光盘已挂载到。信息 (verbose)。(upgrade) 选项。(all) 已安装的包。(package) 选项
259 11
|
2月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
338 1
二、Linux文本处理与文件操作核心命令
|
1月前
|
安全 数据可视化 开发者
有什么值得推荐的网站源码分享下载?
本文指出开发者找优质安全网站源码耗时,介绍了多种获取渠道:有 GitHub 等综合开源社区,虽资源多但新手筛选难;有垂直领域平台,其中 PageAdmin CMS 系统因源码完整、易上手、扩展性强受青睐;还有贴合国内需求的国内社区。同时提醒注意版权与安全检测,助力开发者高效搭建项目。
367 9
|
12天前
|
运维 开发者 Docker
一、Docker:一场颠覆应用部署与运维的容器革命
Docker的出现,就是为了解决“在我电脑上能跑”这个老大难问题。它像个魔法集装箱,把你的程序和它需要的所有东西(比如库、配置)都打包好,这样无论在哪运行,环境都一模一样。理解它很简单,就三个核心玩意儿:镜像是程序的“安装包”,容器是跑起来的程序,而仓库就是存放和分享这些“安装包”的地方。
235 6
|
6月前
|
人工智能 供应链 安全
MCP Server的五种主流架构与Nacos的选择
本文深入探讨了Model Context Protocol (MCP) 在企业级环境中的部署与管理挑战,详细解析了五种主流MCP架构模式(直连远程、代理连接远程、直连本地、本地代理连接本地、混合模式)的优缺点及适用场景,并结合Nacos服务治理框架,提供了实用的企业级MCP部署指南。通过Nacos MCP Router,实现MCP服务的统一管理和智能路由,助力金融、互联网、制造等行业根据数据安全、性能需求和扩展性要求选择合适架构。文章还展望了MCP在企业落地的关键方向,包括中心化注册、软件供应链控制和安全访问等完整解决方案。
2896 158
MCP Server的五种主流架构与Nacos的选择
|
2月前
|
存储 Unix Linux
五、Linux进程与磁盘管理
管理Linux服务器就像身兼两职:既是“医生”,又是“城市规划师”。作为“医生”,你得用ps和top给系统“体检”,看看哪些进程在运行;必要时用kill命令做“外科手术”,终止掉问题进程。作为“规划师”,你得先用fdisk把“土地”(磁盘)划分成“地块”(分区),再用mkfs铺上“地基”(文件系统),最后用mount把地块“挂牌”使用。而df和du就是你随时查看“土地”使用情况的测量工具。
201 2