当前位置:

首页 > 编程开发 > Linux Shell脚本之流程控制语句举例详解

Linux Shell脚本之流程控制语句举例详解

Shell脚本流程控制包含:if/elif/else条件判断实现分支执行;for/while/until循环实现重复任务;case分支选择处理多条件匹配;而break/continue则分别用于跳出当前循环和提前进入下一次循环。这些控制结构共同构成脚本的逻辑基础,使自动化任务灵活高效。

本文目录

    在掌握了Shell脚本的变量与运算之后,流程控制就成了构建复杂脚本的关键环节。它让脚本能够根据不同的条件自行选择执行路径,或者反复执行某个任务,从而实现真正的灵活和自动化。说白了,没有流程控制,脚本就是一条路走到黑,有了它,才能像人一样“判断”和“循环”。

    思维导图

    Linux Shell脚本之流程控制语句举例详解

    Linux Shell脚本之流程控制语句举例详解

    Linux Shell脚本之流程控制语句举例详解

    一、条件判断

    if 语句是条件控制里最基础、最常用的结构。它的核心逻辑很简单:评估一个命令的退出状态码。如果退出码是 0(表示成功),条件就算成立;如果非 0(表示失败),条件就不成立。

    if 的基本结构

    格式:

    if [ 条件判断 ]; then
      # 条件为真时执行的代码块
    fi
    

    代码示例:检查文件是否存在

    #!/bin/bash
    TARGET_FILE="/etc/hosts"
    
    if [ -f "$TARGET_FILE" ]; then
      echo "文件 '$TARGET_FILE' 存在。"
    fi
    

    if...else 结构

    格式:

    if [ 条件判断 ]; then
      # 条件为真时执行的代码块
    else
      # 条件为假时执行的代码块
    fi
    

    代码示例:判断目录是否存在

    #!/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 结构

    格式:

    if [ 条件1 ]; then
      # 条件1为真时执行
    elif [ 条件2 ]; then
      # 条件1为假,但条件2为真时执行
    else
      # 以上所有条件都为假时执行
    fi
    

    代码示例:根据HTTP状态码判断响应

    #!/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(小于等于)

    二、循环结构

    循环用来重复执行一段代码,直到满足某个退出条件为止。Shell提供了几种循环方式,各有各的适用场景。

    for 循环

    for 循环最擅长遍历一个列表——可以是字符串、文件名、数字序列等,也可以写C语言风格的数值循环。

    格式(遍历列表):

    for variable_name in item1 item2 item3 ...; do
      # 循环体
    done
    

    代码示例(遍历并重命名文件):

    #!/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风格数值循环):

    for (( initialization; condition; step )); do
      # 循环体
    done
    

    代码示例(执行三次ping测试):

    #!/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 循环的逻辑是:每次迭代前先检查条件,条件为真就继续执行循环体,直到条件变假为止。

    格式:

    while [ 条件判断 ]; do
      # 循环体
    done
    

    代码示例:逐行读取文件

    #!/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 正好相反:只要条件为假,就继续执行循环体,直到条件变为真才停止。可以理解为“直到……才停止”。

    格式:

    until [ 条件判断 ]; do
      # 循环体
    done
    

    代码示例:等待服务端口启动

    #!/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: 跳过当前循环的剩余部分,直接开始下一次迭代。

    代码示例:在循环中处理文件

    #!/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 更清晰、更直观,特别适合根据单个变量的值来做匹配。

    格式:

    case $variable in
      pattern1)
        # 匹配 pattern1 时执行
        ;;
      pattern2|pattern3)
        # 匹配 pattern2 或 pattern3 时执行
        ;;
      *)
        # 默认情况,当以上模式都不匹配时执行
        ;;
    esac
    

    代码示例:脚本参数解析

    #!/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/messages 或 journalctl -f 的输出,为简化可检查一个普通文件)是否出现了 "critical error" 字符串,一旦出现就打印 "Critical error detected!" 并退出。
    7. 嵌套循环与 break n:写一个嵌套循环。外层循环从1到3,内层循环从1到3。在内层循环中,如果内外两个循环变量(i 和 j)相等,则同时跳出内外两层循环。每次循环都打印当前的 i 和 j 的值。
    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. 文件权限检查:
    #!/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 是文件测试操作符,分别检查读、写、执行权限。&& 是逻辑与操作符,要求所有条件都为真才执行 then 块。
    1. 字符串与逻辑判断:
    #!/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 来精确控制循环,直接打印出范围内的偶数。
    1. for 循环与通配符:
    #!/bin/bash
    for logfile in /var/log/*.log; do
      if [ -s "$logfile" ]; then
        echo "找到非空日志文件: $(basename "$logfile")"
      fi
    done
    
    • 解析: *.log 是一个通配符,for 循环会遍历所有匹配的文件名。-s 文件测试操作符用于判断文件大小是否大于零。basename 命令用于提取文件名,去除路径。
    1. 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。
    1. until 循环与命令退出码:
    #!/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 循环的条件是命令本身(grep -q ...)。只要 grep 找不到字符串(退出码非0,条件为假),循环就继续。一旦找到(退出码为0,条件为真),循环终止。
    1. 嵌套循环与 break n:
    #!/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 语句与通配符:
    #!/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 语句的模式支持通配符,如 *(匹配任意字符序列)。| 用于分隔多个模式,表示“或”。
    1. select 菜单:
    #!/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 中。

    总结

    流程控制是Shell脚本从“简单顺序执行”走向“智能自动化”的分水岭。条件判断让脚本能根据实际情况做决策,循环结构让重复工作变得轻松,分支选择则让代码更清晰易读。配合上 break、continue 这些控制语句,几乎可以应对所有日常运维和开发中的自动化需求。掌握好这些基础,再复杂的脚本也能拆解出清晰的逻辑。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    Linux编程环境
    Linux编程环境

    接触Linux编程,首先得摸清它的脾气,理解几个关键点,再熟悉一下手头的工具,才能事半功倍。 一、Linux下的编程环境 在Linux系统的程序设计中,有一些重要特性要特别注意: 1. Linux天生就是多任务系统。同一时刻可以跑很多进程或线程,所以千万别以为你的程序是唯一的实例,同一个用户或不同用

    这些操作系统你一定听过!
    这些操作系统你一定听过!

    本文公众号来源:Java建设者作者:cxuan本文已收录至我的GitHub操作系统概念大部分操作系统提供了特定的基础概念和抽象,例如进程、地址空间、文件等,它们是需要理解的核心内容。下面我们会简要介绍一些基本概念,为了说明这些概念,我们会不时的从UNIX中提出示例,相同的示例也会存在于其他系统中,我们后面会进行介绍。进程操作系统一个很关键的概念就是进程(Process)。进程的本质就是操作系统执行的一个程序。与每个进程相关的是地址空间(addressspace),这是从某个最小值的存储位置(通常是

    Metasploit payload收藏指南
    Metasploit payload收藏指南

    通常Metasploit最有用(对于初学者来说被低估)的功能之一是msfpayload模块。可以使用此模块创建多个有效负载,它有助于在几乎任何情况下为您提供外壳。对于这些有效负载中的每一个,您都可以进入msfconsole并选择exploit/multi/handler。为使用的相关负载运行“设置负载”并配置所有必要的选项(LHOST、LPORT等)。执行并等待有效负载运行。对于下面的示例,它是不言自明的,但LHOST应填写您的IP地址(如果在网络内进行攻击,则为LANIP,如

    PHP 函数和 Shell 函数的区别
    PHP 函数和 Shell 函数的区别

    PHP函数和Shell函数的主要区别在于安全性(PHP函数更安全)、可靠性(Shell函数因操作系统而异)、功能(Shell函数更强大但受shell限制)、性能(PHP函数通常更快)和复杂性(Shell函数更复杂)。它们都用于文件系统、进程和命令操作,但PHP函数是内置的,而Shell函数通过外部shell调用。因此,在服务器文件下载场景中,file_put_contents()函数更安全,而wget命令更灵活。

    Linux帮助命令
    Linux帮助命令

    在本指南中,我们将演示如何在Linux中使用”help”命令。先决条件:要执行本指南中演示的步骤,您需要以下组件:一个功能齐全的Linux系统。出于测试和学习的目的,LinuxVM可以很好地工作。对命令行界面有基本了解帮助命令在使用CLI时,我们通常与一个shell程序进行交互,这个程序充当着操作系统的底层接口。目前,Bash是最常用的shell程序之一,多数Linux系统默认采用Bash作为其shell。“help”命令是Bash的内置shell命令。它用于浏览其他内置命令的sh

    Linux Shell脚本中特殊字符的用法
    Linux Shell脚本中特殊字符的用法

    在LinuxShell脚本中,预定义了一些特殊参数,它们分别代表不同的含义和返回值,下面逐一进行总结。1.【$0】:脚本名$0返回当前执行的shell脚本的名称。2.【1-9】:命令行参数1到9$1-$9这9个分别代表脚本执行命令第一个参数、第二个参数、第三个参数……第9个参数。例如,假设我们有一个名为test.sh的Shell脚本,它的内容如下:#!/bin/bashecho"Scriptname:$0"echo"Firstargument:$1"echo"Secondargument:$2"在运行脚本

    用Shell脚本在Linux上创建一个能够自动解压文件的脚本
    用Shell脚本在Linux上创建一个能够自动解压文件的脚本

    前几天在使用阿里云时候发现阿里工程师提供的一个脚本里,后面都是乱码加密文件,并且文件只要一更改自解压就会失效,心里是什么技术进行代码加密,仔细查看代码后发现,原来是.tar.gz的二进制文件,把打包压缩以后的文件进行直接存进shell脚本后面,从而实现自解压,次篇文件使用tar编码进行嵌入存文件。一、系统环境说明Centos7系统shell使用自带bash二、开始编码测试1.先来看看阿里工程师编写的部分代码,从代码可以看出后面一连串的乱码是一个.tar.gz的打包压缩文件,可以看到是使用awk进行获取.t

    Linux Shell编程入门指南
    Linux Shell编程入门指南

    你是否曾经想过,如何通过编写简单的脚本来自动化你的日常任务,提高工作效率?在Linux操作系统下,Shell编程为你提供了这样的机会。本文将引领您进入Shell编程的世界,涵盖基础知识、常见应用和最佳实践,帮助您轻松掌握Shell编程的精华。一、Shell编程基础1.Shell脚本是什么?Shell脚本是一组按顺序执行的Shell命令和控制结构,保存在文本文件中。通过运行Shell脚本,我们可以自动化执行一系列任务,从而节省时间和精力。2.变量:数据的存储与引用在Shell脚本中,我们可以使用变量来存储数

    创建Linux自解压文件的Shell脚本
    创建Linux自解压文件的Shell脚本

    在Linux系统中,有时候需要将程序或文件打包成自解压文件,以便于传播和安装。本文概述了使用Shell脚本创建Linux自解压文件的基本方法和步骤。一、准备压缩包和Shell脚本首先,准备一个压缩包,包含需要分发的程序或文件,然后编写Shell脚本以执行解压和安装步骤。这里假设有一个名为my_program.tar.gz的压缩包文件,以及一个名为install_script.sh的Shell脚本文件。二、合并自解压文件接下来,使用以下命令将Shell脚本文件和压缩包文件合并为一个自解压文件:catinst

    Linux脚本学习笔记,log函数使用技巧
    Linux脚本学习笔记,log函数使用技巧

    本文描述了一个用于记录shell脚本执行日志的日志脚本函数。在进行shell脚本开发时,经常需要监控系统数据。为了方便查看,我们可以将脚本运行情况记录为日志文件,避免需要一直在命令控制台上监视。需求:1、可以记录脚本的运行情况;2、可以记录时间;3、可以在输入log达到一定的行数后对以前的log进行删减,防止log文件无限累积;需求分析这个简单需求可以通过编写一个函数来实现,该函数能够将脚本中的日志信息输出到同名的log文件中,方便开发人员日后查阅分析脚本运行情况。可以根据个人喜好和技术能力选择合适的方式

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。