while 循环

while 循环在条件为真时重复执行,适合条件驱动的场景。和 for 循环不同,while 不需要提前知道循环次数。

基本语法

while [ 条件 ]; do
    命令
done

条件为真时执行循环体,条件为假时退出。

基本示例

COUNT=1

while [ $COUNT -le 5 ]; do
    echo "计数: $COUNT"
    COUNT=$((COUNT + 1))
done

读取文件

while 最常见的用途是逐行读取文件:

# 方式一
while read LINE; do
    echo "行: $LINE"
done < file.txt

# 方式二(保留空格)
while IFS= read -r LINE; do
    echo "行: $LINE"
done < file.txt

# 方式三(读取多列)
while read COL1 COL2 REST; do
    echo "第一列: $COL1"
    echo "第二列: $COL2"
done < data.txt

IFS= 防止行首行尾空格被去掉,-r 防止反斜杠被转义。

读取用户输入

while true; do
    read -p "请输入 (q 退出): " INPUT
    if [ "$INPUT" = "q" ]; then
        break
    fi
    echo "你输入了: $INPUT"
done

无限循环

# 方式一
while true; do
    echo "执行中..."
    sleep 1
done

# 方式二
while :; do
    echo "执行中..."
    sleep 1
done

# 方式三
while [ 1 ]; do
    echo "执行中..."
    sleep 1
done

带条件的循环

# 等待服务启动
MAX_RETRY=10
COUNT=0

while [ $COUNT -lt $MAX_RETRY ]; do
    if curl -s http://localhost:8080/health > /dev/null; then
        echo "服务已启动"
        break
    fi
    echo "等待服务启动... ($((COUNT+1))/$MAX_RETRY)"
    sleep 2
    COUNT=$((COUNT + 1))
done

if [ $COUNT -eq $MAX_RETRY ]; then
    echo "服务启动超时"
    exit 1
fi

读取命令输出

# 逐行处理命令输出
ps aux | while read USER PID REST; do
    if [ "$USER" = "root" ]; then
        echo "root 进程: $PID"
    fi
done

# 注意:管道后的 while 在子 Shell 中执行,变量不会保留
# 解决方案:用进程替换
while read LINE; do
    VAR="value"
done < <(some_command)
echo $VAR  # 可以访问

多条件循环

A=0
B=10

while [ $A -lt 5 ] && [ $B -gt 5 ]; do
    echo "A=$A, B=$B"
    A=$((A + 1))
    B=$((B - 1))
done

嵌套 while

I=1
while [ $I -le 3 ]; do
    J=1
    while [ $J -le 3 ]; do
        echo "I=$I, J=$J"
        J=$((J + 1))
    done
    I=$((I + 1))
done

实际应用

监控脚本

#!/bin/bash

LOG_FILE="/var/log/app.log"

tail -f "$LOG_FILE" | while read LINE; do
    if echo "$LINE" | grep -q "ERROR"; then
        echo "发现错误: $LINE"
        # 发送告警
    fi
done

批量处理带进度

#!/bin/bash

FILES=(*.txt)
TOTAL=${#FILES[@]}
CURRENT=0

while [ $CURRENT -lt $TOTAL ]; do
    FILE="${FILES[$CURRENT]}"
    echo "处理 ($((CURRENT+1))/$TOTAL): $FILE"
    # 处理逻辑
    CURRENT=$((CURRENT + 1))
done

倒计时

#!/bin/bash

SECONDS=10

while [ $SECONDS -gt 0 ]; do
    echo -ne "倒计时: $SECONDS 秒\r"
    sleep 1
    SECONDS=$((SECONDS - 1))
done
echo -e "\n时间到!"

重试机制

#!/bin/bash

MAX_RETRY=3
RETRY=0

while [ $RETRY -lt $MAX_RETRY ]; do
    if ssh user@server "echo 连接成功"; then
        break
    fi
    RETRY=$((RETRY + 1))
    echo "连接失败,重试 $RETRY/$MAX_RETRY"
    sleep 2
done

while 与 for 的选择

用 while 的场景:

  • 不知道循环次数
  • 逐行读取文件
  • 等待某个条件
  • 无限循环

用 for 的场景:

  • 遍历列表、数组
  • 已知循环次数
  • 遍历文件名

小结

while 循环要点:

  1. 条件为真时持续执行
  2. 逐行读文件用 while read
  3. 无限循环用 while true
  4. 注意管道后的变量作用域
  5. 适合条件驱动的场景