文章目录

Shell 脚本控制结构:if、for、while

发布于 2026-04-06 02:07:02 · 浏览 14 次 · 评论 0 条

Shell 脚本控制结构:if、for、while

Shell 脚本的核心能力在于自动化处理重复任务。掌握条件判断和循环控制,就掌握了脚本编程的半壁江山。本文手把手讲解 ifforwhile 三大控制结构的完整语法实战用法,帮助你从入门到实战。


1 条件判断:if 语句

if 语句用于根据条件执行不同分支。它是 Shell 脚本中最基础也是最重要的控制结构。

1.1 基本语法

if [ 条件 ]; then
    # 条件成立时执行的命令
fi

注意:[] 是测试命令,两侧必须保留空格fiif 的反向拼写,表示条件结束。

1.2 带分支的写法

if [ 条件 ]; then
    # 条件成立时执行的命令
else
    # 条件不成立时执行的命令
fi

1.3 多分支写法

if [ 条件1 ]; then
    # 条件1成立时执行
elif [ 条件2 ]; then
    # 条件2成立时执行
else
    # 所有条件都不成立时执行
fi

1.4 常用比较运算符

运算符 含义 示例
-eq 等于(数值) [ $a -eq 5 ]` | | `-ne` | 不等于(数值) | `[ $a -ne 0 ]
-gt 大于(数值) [ $a -gt 10 ]` | | `-ge` | 大于等于(数值) | `[ $a -ge 5 ]
-lt 小于(数值) [ $a -lt 3 ]` | | `-le` | 小于等于(数值) | `[ $a -le 8 ]
= 等于(字符串) [ "$name" = "admin" ]` | | `!=` | 不等于(字符串) | `[ "$status" != "ok" ]
-z 字符串为空 [ -z "$input" ]` | | `-n` | 字符串非空 | `[ -n "$path" ]
-f 文件存在且是普通文件 [ -f "/etc/config" ]
-d 目录存在 [ -d "/tmp/logs" ]
-x 文件可执行 `[ -x "$script" ]` | ### 1.5 复合条件 使用 `-a` 表示"与",`-o` 表示"或",或使用 `&&` 和 `||`。 ```bash # 使用 -a 和 -o if [ $age -ge 18 -a $age -lt 60 ]; then echo "成年人" fi # 使用 && 和 ||(更推荐) if [ $status = "ok" ] && [ $count -gt 0 ]; then echo "状态正常且有数据" fi if [ -f "$file" ]

elif [ $MEMORY -gt 500 ]; then echo "注意:内存使用率中等,当前使用 ${MEMORY}MB"
else
echo "正常:内存使用率良好,当前使用 ${MEMORY}MB" fi ``` --- ## 2 循环结构:for 循环 `for` 循环用于**已知迭代次数**或**遍历集合**的场景。它逐个处理列表中的元素,结构清晰。 ### 2.1 基本语法:遍历列表 ```bash for 变量 in 项目1 项目2 项目3; do echo "当前处理: $变量"
done


### 2.2 使用花括号生成序列

```bash
# 遍历 1 到 5
for i in {1..5}; do
    echo "数字: $i"
done

# 遍历 0 到 10,步长为 2
for i in {0..10..2}; do
    echo "偶数: $i"
done

2.3 C 风格 for 循环

for ((i=1; i<=5; i++)); do
    echo "第 $i 次循环"
done
```

### 2.4 遍历文件和目录

```bash
# 遍历当前目录下的所有文件
for file in *; do
    echo "文件: $file"
done

# 遍历特定目录
for conf in /etc/*.conf; do
    echo "配置文件: $conf"
done

# 遍历所有参数
for arg in "$@"; do
    echo "参数: $arg"
done
```

### 2.5 实战示例:批量处理文件

```bash
#!/bin/bash

# 备份所有 .txt 文件
for txtfile in *.txt; do
    if [ -f "$txtfile" ]; then
        cp "$txtfile" "${txtfile%.txt}_backup.txt"
        echo "已备份: $txtfile"
    fi
done
```

### 2.6 for 循环与数组

```bash
# 定义数组
services=("nginx" "mysql" "redis")

# 遍历数组
for service in "${services[@]}"; do
    systemctl status "$service" > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "$service 正在运行"
    fi
done
```

---

## 3 循环结构:while 循环

`while` 循环用于**条件驱动**的场景。只要条件为真,就持续执行循环体。适合处理未知迭代次数的任务。

### 3.1 基本语法

```bash
while [ 条件 ]; do
    # 循环执行的命令
done
```

### 3.2 实战示例:读取文件逐行处理

```bash
#!/bin/bash

# 逐行读取 users.txt
while IFS= read -r line; do
    echo "用户: $line"
done < users.txt

IFS= 防止行首空格被丢弃,-r 防止反斜杠被解释。

3.3 计数器模式

#!/bin/bash

count=1
while [ $count -le 10 ]; do
    echo "计数: $count"
    count=$((count + 1))
done
```

### 3.4 无限循环与退出

```bash
#!/bin/bash

# 无限循环(按 Ctrl+C 退出)
while true; do
    echo "系统运行中..."
    sleep 60
done
```

结合 `break` 和 `continue` 控制循环:

```bash
#!/bin/bash

for i in {1..10}; do
    if [ $i -eq 3 ]; then
        continue  # 跳过 3
    fi
    if [ $i -eq 7 ]; then
        break     # 退出循环
    fi
    echo "数字: $i"
done

输出结果:1、2、4、5、6。

3.5 实战示例:监控服务直到启动

#!/bin/bash

service_name="nginx"
max_attempts=10
attempt=0

while [ $attempt -lt $max_attempts ]; do
    if systemctl is-active --quiet "$service_name"; then
        echo "$service_name 已启动"
        exit 0
    fi
    attempt=$((attempt + 1))
    echo "等待启动... (尝试 $attempt/$max_attempts)"
    sleep 2
done

echo "启动失败:$service_name"
exit 1

4 高级技巧与最佳实践

4.1 read 命令结合循环

#!/bin/bash

echo "输入 'quit' 退出"

while read -p "请输入命令: " cmd; do
    if [ "$cmd" = "quit" ]; then
        break
    fi
    echo "执行: $cmd"
done

4.2 使用管道时的陷阱

注意:管道会创建子 Shell,变量修改不会影响父 Shell。

#!/bin/bash

count=0
cat file.txt | while read line; do
    count=$((count + 1))  # 这个修改不会生效
done
echo "行数: $count"  # 输出 0

正确做法是使用进程替换重定向

#!/bin/bash

count=0
while read line; do
    count=$((count + 1))
done < <(cat file.txt)
echo "行数: $count"  # 正确输出

4.3 循环中的错误处理

#!/bin/bash

for file in /data/*.csv; do
    [ -f "$file" ] || continue  # 跳过不存在的文件
    
    if ! process_file "$file"; then
        echo "处理失败: $file" >&2
        continue
    fi
    echo "处理成功: $file"
done

5 综合实战:自动化部署脚本

#!/bin/bash

# 自动化部署脚本示例

DEPLOY_DIR="/opt/app"
BACKUP_DIR="/opt/backup"
TIMESTAMP=$(date +%Y%m%d%H%M%S)

# 步骤 1:检查必要条件
if [ ! -d "$DEPLOY_DIR" ]; then
    echo "创建部署目录: $DEPLOY_DIR"
    mkdir -p "$DEPLOY_DIR"
fi

# 步骤 2:备份旧版本
if [ -d "$DEPLOY_DIR/current" ]; then
    backup_name="backup_$TIMESTAMP"
    cp -a "$DEPLOY_DIR/current" "$BACKUP_DIR/$backup_name"
    echo "已备份到: $BACKUP_DIR/$backup_name"
fi

# 步骤 3:下载并解压新版本
for arch in x86_64 aarch64; do
    filename="app-$arch"
    url="https://example.com/downloads/$filename"
    
    echo "下载: $filename"
    if wget -q "$url" -O "/tmp/$filename.tar.gz"; then
        tar -xzf "/tmp/$filename.tar.gz" -C "$DEPLOY_DIR"
        echo "解压完成: $filename"
    else
        echo "下载失败: $filename"
    fi
done

# 步骤 4:验证部署结果
success=0
for binary in "$DEPLOY_DIR"/*/app; do
    if [ -x "$binary" ]; then
        if "$binary" --version > /dev/null 2>&1; then
            echo "验证通过: $binary"
            success=$((success + 1))
        fi
    fi
done

echo "部署完成,成功验证 $success 个组件"

6 语法速查表

结构 语法模式 适用场景
if if [ 条件 ]; then ... fi 条件分支、状态检查
for-in for 变量 in 列表; do ... done 遍历已知集合、文件列表
for-C for ((i=0; i<n; i++)); do ... done 精确计数、序号迭代
while while [ 条件 ]; do ... done 条件驱动、未知迭代次数
until until [ 条件 ]; do ... done 直到条件成立(反向 while)
break break [n] 跳出 n 层循环
continue continue [n] 跳到下一次循环

Shell 脚本的控制结构看似简单,但组合使用能解决绝大多数自动化问题。记住三点原则if 判断条件要严谨,for 用于遍历已知内容,while 用于条件驱动。勤写脚本,多实践,才能真正掌握。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文