当前位置:首页 > 技术 > 正文内容

Shell 脚本流程控制指南:循环逻辑与条件分支

访客 技术 2026年8月5日 1

一、迭代循环机制(For Loop)

在 Shell 脚本中,for 语句用于处理需要重复执行的操作。根据遍历对象的不同,主要分为列表迭代、参数迭代以及类 C 语言风格的计数循环三种形式。

1. 序列列表迭代

此模式适用于已知具体元素列表或数值范围的情况。它将列表中的每个值依次赋值给变量,并执行命令块。

# 基础语法结构
for current_item in sequence; do
    # 处理当前项
done

场景演示: 遍历文件列表或数值区间。

#!/bin/bash
# 遍历指定目录下的脚本文件
target_dir="/opt/scripts"
for file_path in "$target_dir"/*.sh; do
    echo "发现文件:$file_path"
done

# 生成网络段 IP 地址示例 (192.168.1.1 至 192.168.1.10)
base_ip="192.168.1"
for last_octet in {1..10}; do
    echo "${base_ip}.${last_octet}"
done

2. 命令行参数迭代

当未指定列表时,for 循环会默认遍历传递给脚本的所有位置参数。

#!/bin/bash
count=0
for arg in "$@"; do
    echo "参数 ${count}: $arg"
    ((count++))
done
echo "接收到的总参数数量:$#" 

3. 类 C 风格计数循环

这种格式更接近传统编程语言,包含初始化、条件判断和步进表达式。

# 语法模板
for (( init_expr; condition; increment )); do
    commands
done

实际应用: 构建九九乘法表。

#!/bin/bash
for (( row=1; row<=9; row++ )); do
    for (( col=1; col<=row; col++ )); do
        result=$((row * col))
        printf "%d*%d=%-2d\t" "$col" "$row" "$result"
    done
    echo ""
done

视觉化案例: 绘制 8x8 棋盘格(使用 ANSI 转义码控制颜色)。

#!/bin/bash
for (( i=1; i<=8; i++ )); do
    for (( j=1; j<=8; j++ )); do
        sum_coord=$((i + j))
        if (( sum_coord % 2 == 0 )); then
            # 偶数和显示白色背景
            echo -ne "\033[47m \033[0m"
        else
            # 奇数和显示黑色背景
            echo -ne "\033[40m \033[0m"
        fi
    done
    echo ""
done

循环控制指令

  • break: 终止当前循环层级的执行。
  • continue: 跳过本次剩余代码,直接进入下一轮迭代。
  • exit: 直接退出整个脚本进程。

筛选奇数求和示例:

#!/bin/bash
total_sum=0
for (( n=1; n<=100; n++ )); do
    if (( n % 2 == 0 )); then
        continue # 跳过偶数
    fi
    total_sum=$((total_sum + n))
done
echo "1 到 100 的奇数总和为:$total_sum"

二、条件驱动循环(While & Until)

1. While 循环

只要测试条件为真(True),就持续执行循环体。常用于不知道确切次数但满足某个条件即停止的场景。

while [ test_condition ]; do
    action
done

实时监控案例: 检查用户登录状态。

#!/bin/bash
target_user="admin"
echo "开始监控用户 '$target_user'..."
while ! who | grep -q "^$target_user "; do
    echo "$(date): 用户尚未上线,等待检测..."
    sleep 5
done
echo "检测到用户已登录!"

2. Until 循环

逻辑与 while 相反,当条件为假(False)时执行循环,直到条件变为真才停止。

until [ test_condition ]; do
    action
done

差异对比:

  • while: 条件满足则执行。
  • until: 条件不满足则执行。

批量建用户实战: 前 5 个指定 UID,后 5 个指定家目录。

#!/bin/bash
counter=1
limit=10

# 确保基础目录存在
[ ! -d /rhome ] && mkdir -p /rhome

until (( counter > limit )); do
    username="user${counter}"
    if (( counter <= 5 )); then
        # 自定义 UID (1001-1005)
        uid_val=$((1000 + counter))
        useradd -u "$uid_val" "$username"
        echo "Created $username with UID $uid_val"
    else
        # 自定义家目录
        home_path="/rhome/$username"
        useradd -d "$home_path" "$username"
        echo "Created $username with Home $home_path"
    fi
    
    # 统一设置临时密码
    echo "TempPass123" | passwd --stdin "$username" &>/dev/null
    ((counter++))
done

三、并发执行优化

在进行网络探测等耗时操作时,串行执行效率较低。可以通过后台运行(&)结合 wait 实现并发。

#!/bin/bash
network_range="192.168.1"
alive_list="/tmp/hosts_alive.log"
down_list="/tmp/hosts_down.log"

# 清空旧日志
> "$alive_list"
> "$down_list"

for (( ip=1; ip<=50; ip++ )); do
    (
        ping -c 1 -W 1 "${network_range}.${ip}" &>/dev/null
        if [[ $? -eq 0 ]]; then
            echo "${network_range}.${ip} UP" >> "$alive_list"
        else
            echo "${network_range}.${ip} DOWN" >> "$down_list"
        fi
    ) &
done

# 等待所有后台任务完成
wait
echo "扫描结束。存活主机:$(wc -l < "$alive_list")"

四、多路分支选择(Case Statement)

case 结构用于匹配变量值与多个模式,适合处理菜单选项或服务控制脚本。

基本语法

case $variable in
    pattern1)
        # 动作组 1
        ;;
    pattern2)
        # 动作组 2
        ;;
    *)
        # 默认动作
        ;;
esac

服务管理脚本示例

模拟一个简易的服务守护进程启动控制器。

#!/bin/bash
SERVICE_NAME="${1:-default}"
ACTION="${2:-status}"

check_service() {
    case "$ACTION" in
        start)
            systemctl start "$SERVICE_NAME" && echo "Service started." || echo "Start failed."
            ;;
        stop)
            systemctl stop "$SERVICE_NAME" && echo "Service stopped." || echo "Stop failed."
            ;;
        restart)
            systemctl restart "$SERVICE_NAME" && echo "Service restarted." || echo "Restart failed."
            ;;
        status)
            systemctl is-active "$SERVICE_NAME"
            ;;
        *)
            echo "Unknown action: $ACTION. Try: start, stop, restart, status"
            exit 1
            ;;
    esac
}

if [ -z "$SERVICE_NAME" ]; then
    echo "Usage: $0  <action>"
    exit 1
fi

check_service

交互式维护菜单

集成 while 循环以支持多次交互。

#!/bin/bash
show_menu() {
    echo "=== System Monitor Menu ==="
    echo "C - CPU Usage"
    echo "M - Memory Info"
    echo "D - Disk Space"
    echo "Q - Quit Program"
    echo "========================"
}

while true; do
    show_menu
    read -p "Enter choice: " option
    
    case "$option" in
        c|C) 
            top -bn1 | head -n 5 
            ;;
        m|M) 
            free -h 
            ;;
        d|D) 
            df -h 
            ;;
        q|Q) 
            echo "Exiting..."
            break
            ;;
        *) 
            echo "Invalid selection."
            ;;
    esac
    echo "--- Press Enter to continue ---"
    read
done

五、嵌套逻辑综合应用

在处理复杂业务逻辑时,往往需要在循环内部进行条件判断,或在分支中包含循环。

质数判定优化

无需遍历所有数字,只需检查至平方根即可。

#!/bin/bash
read -p "Enter a positive integer: " num

if (( num < 2 )); then
    echo "$num is not a prime number."
    exit 0
fi

is_prime=1
# 仅遍历到开方值的整数部分
max_check=$(echo "sqrt($num)" | bc)
for (( k=2; k<=max_check; k++ )); do
    if (( num % k == 0 )); then
        is_prime=0
        break
    fi
done

if (( is_prime == 1 )); then
    echo "$num is a Prime Number."
else
    echo "$num is Not a Prime Number."
fi

闰年逻辑校验

能被 4 整除且不能被 100 整除,或者能被 400 整除。

#!/bin/bash
read -p "Check Year: " year

if (( year % 400 == 0 )) || (( year % 4 == 0 && year % 100 != 0 )); then
    echo "$year is a Leap Year."
else
    echo "$year is a Common Year."
fi

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。