四、shell脚本--流程控制语句:指挥脚本“走哪条路”

前面我们学了变量和运算,相当于给脚本准备了“原料”和“工具”。现在,我们要学习怎么指挥脚本根据不同的情况选择不同的执行路径,或者重复执行某些任务。这就是流程控制要做的事情,它能让你的脚本变得更加灵活自动化

1. 条件判断:如果这样,就那样 (if 语句)

(这部分与上一版本相同,包含 if, if...else, if...elif...else, test, [ ] 的讲解和示例)

生活中我们常做选择:“如果天冷,多穿件衣服”。Shell 脚本里的 if 语句就是用来做这种判断的。它看某个条件满足不满足,然后决定接下来该执行哪些命令。

if 的基本样子:满足条件才执行

结构:

if [ 条件判断命令 ]; then
# 条件为真 (命令成功,退出码 0) 时执行这里的代码
要执行的命令...
fi
# fi 表示 if 语句块结束

示例:检查文件是否存在

#!/bin/bash
check_file="/etc/hosts"
echo "正在检查文件: $check_file"
if [ -f "$check_file" ]; then
echo "<font color='green'>文件 '$check_file' 找到了!</font> 👍"
fi
echo "检查完毕。"
if...else:二选一,总得走一边

结构:

if [ 条件判断命令 ]; then
# 条件为真时执行
命令组A
else
# 条件为假 (命令失败,退出码非 0) 时执行
命令组B
fi

示例:判断数字是正是负(简化版)

#!/bin/bash
number=-5
echo "给定的数字是: $number"
if [ $number -gt 0 ]; then
echo "这是一个正数。"
else
echo "这不是一个正数 (可能是负数或零)。"
fi
if...elif...else:多重条件,逐个尝试

结构:

if [ 条件1 ]; then
命令组1
elif [ 条件2 ]; then
命令组2
elif [ 条件3 ]; then
命令组3
else
默认命令组
fi

示例:根据分数评级

#!/bin/bash
score=75
echo "你的分数是: $score"
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
elif [ $score -ge 60 ]; then
echo "及格"
else
echo "需要加油"
fi
条件怎么写?认识 test 命令和 [ ]

(包含 test[ ] 的讲解和示例,以及它们的常见判断类型和注意事项,同上)
… (此处省略与上一版本相同的 test[ ] 内容) …

2. 循环结构:让任务跑起来 🏃‍♀️🔁

有时候我们需要重复执行一系列命令,比如处理一堆文件,或者等某个条件满足。这时候就要用到循环了。

for 循环:挨个处理列表中的成员 或 进行数值循环

for 循环非常强大,既能遍历一个列表,也能像 C 语言那样进行数值控制的循环。

格式 (遍历字符串列表):

for 变量名 in 字符串1 字符串2 ... ; do
# 处理 $变量名
循环体命令...
done

示例 (遍历字符串列表):

#!/bin/bash
echo "遍历颜色列表:"
for color in red green blue; do
echo "当前颜色是: $color"
done

格式 (遍历文件名 - 通配符):

for 变量名 in *.扩展名; do
# 处理 $变量名 (文件名)
循环体命令...
done

示例 (遍历文件名):

#!/bin/bash
echo "查找当前目录的 .log 文件:"
for logfile in *.log; do
if [ -f "$logfile" ]; then
echo "找到日志文件: $logfile"
else
echo "<font color='gray'>没有找到 .log 文件或通配符本身。</font>"
break
fi
done

格式 (遍历数字序列 - 花括号扩展):

for 变量名 in {开始..结束..步长}; do
# 处理 $变量名 (数字)
循环体命令...
done

示例 (遍历数字序列):

#!/bin/bash
echo "打印数字 1 到 3:"
for i in {1..3}; do
echo "数字: $i"
done

格式 (遍历命令输出):

for 变量名 in $(命令); do
# 处理 $变量名 (命令输出的每个词/行)
循环体命令...
done

示例 (遍历命令输出):

#!/bin/bash
echo "列出 /etc/ 下的目录 (简化示例):"
for dir_name in $(ls -p /etc | grep '/$' | sed 's/\///'); do
if [ -n "$dir_name" ]; then
echo "找到子目录: $dir_name"
fi
done

C 语言风格的 for 循环 (数值循环) 新增部分
这种格式特别适合需要精确控制循环次数、或者有明确起始值、结束条件和步进的数值循环场景。它的语法和 C 语言非常相似。

格式:

for (( 初始化表达式; 循环条件; 迭代表达式 )); do
# 循环体命令...
done
  • 初始化表达式: 在循环开始前执行一次,通常用来设置计数器的初始值 (例如 i=1)。
  • 循环条件: 在每次循环开始前进行判断。如果条件为 (计算结果非 0),就执行循环体;如果为 (计算结果为 0),就退出循环。 (例如 i<=10)
  • 迭代表达式: 在每次循环体执行完毕后执行,通常用来更新计数器的值 (例如 i++i+=2)。

示例:打印数字 0 到 4

#!/bin/bash
echo "使用 C 风格 for 循环打印 0 到 4:"
# 注意:双括号内变量名不需要加 $
for (( count=0; count<5; count++ )); do
echo "当前计数值是: $count"
done

示例:反向计数

#!/bin/bash
echo "反向计数从 5 到 1:"
for (( num=5; num>=1; num-- )); do
echo "倒计时: $num"
done

for ((...)) 的优点:

  • 语法清晰,对于有 C/Java 等背景的人来说很熟悉。
  • 双括号内进行的是算术运算,可以直接写 i++, i<=10 等,非常方便。
  • while 循环配合外部计数器变量更紧凑
while 循环:条件满足就一直做

(讲解和示例保持不变)
结构:

while [ 条件判断命令 ]; do
# 只要条件为真,就一直执行这里的命令
循环体命令
# 别忘了在循环体里通常需要有能改变条件的步骤,否则可能死循环!
done

示例:计数器,从 1 数到 5

#!/bin/bash
counter=1
while [ $counter -le 5 ]; do
echo "当前计数: $counter"
counter=$((counter + 1))
done
echo "循环结束!"
until 循环:直到条件满足才停

(讲解和示例保持不变)
结构:

until 条件判断命令; do
# 只要条件为假,就一直执行这里的命令
循环体命令
# 同样,需要有改变条件的步骤
done

示例:模拟等待某个文件出现

#!/bin/bash
file_to_wait="/tmp/ready.flag"
count=0
until [ -f "$file_to_wait" ]; do
count=$((count + 1))
echo "等待文件 $file_to_wait 出现... (第 $count 次检查)"
sleep 2
if [ $count -ge 5 ]; then
echo "等待超时!"
exit 1
fi
done
echo "文件 $file_to_wait 终于出现了!"
循环控制:breakcontinue

(讲解和示例保持不变)

  • break 💥: 立刻终止当前所在的整个循环。
  • continue ⏭️: 立刻结束当前这一轮循环,直接开始下一次

示例:

#!/bin/bash
echo "--- break 示例 ---"
for fruit in apple banana cherry date elderberry; do
echo "检查水果: $fruit"
if [[ "$fruit" == *"b"* ]]; then
echo "找到了带 'b' 的水果 ($fruit),停止查找!"
break
fi
done
echo "查找结束。"

echo "--- continue 示例 ---"
for i in {1..10}; do
if [ $((i % 2)) -eq 0 ]; then
continue # 跳过偶数
fi
echo "奇数: $i"
done

3. 分支选择:多条路选一条 (case 语句)

(讲解和示例保持不变)

结构:

case $变量 in
模式1)
命令组1
;;
模式2 | 模式3)
命令组2
;;
*) # 默认情况
默认命令组
;;
esac

示例:

#!/bin/bash
read -p "请输入一个命令 (start/stop/status): " action
echo "你输入的操作是: $action"
case $action in
start | begin)
echo "正在启动服务..."
;;
stop | halt)
echo "正在停止服务..."
;;
status | stat)
echo "正在检查服务状态..."
;;
*)
echo "<font color='red'>不认识的命令 '$action'!</font>"
;;
esac
echo "Case 处理完成。"

流程控制语句练习题 🧠✍️

(练习题和答案保持不变,因为新增的 for ((...)) 循环主要用于数值循环,相关概念已在 while 循环题目中有所体现)

题目一:if 语句基础
❓ 写一个脚本,判断当前目录下是否存在一个名为 config.txt普通文件。如果存在,打印 “配置文件存在”;如果不存在,打印 “配置文件不存在”。

题目二:if...elif...else
❓ 写一个脚本,接收一个数字作为参数 ($1)。如果数字大于 0,打印 “正数”;如果小于 0,打印 “负数”;如果等于 0,打印 “零”。

题目三:for 循环遍历
❓ 写一个 for 循环,打印出 apple, banana, cherry 这三个水果的名字,每个水果名字占一行。

题目四:while 循环计数
❓ 使用 while 循环,计算从 1 加到 10 的总和,并打印最终结果。

题目五:until 循环等待
❓ (概念题)while [ ! -f file.lock ]until [ -f file.lock ] 这两种写法在逻辑上是否等价?它们都是用来做什么的?

题目六:循环控制 break
❓ 在一个从 1 循环到 20 的 for 循环中,如果遇到数字 13,就立刻停止整个循环。写出这个循环。

题目七:循环控制 continue
❓ 写一个 for 循环,打印 1 到 10 之间所有不是 3 的倍数的数字。

题目八:case 语句选择
❓ 写一个 case 语句,根据变量 command 的值执行不同操作:如果值是 start,打印 “启动服务”;如果是 stop,打印 “停止服务”;如果是 restart,打印 “重启服务”;对于其他任何值,打印 “未知命令”。


参考答案 ✅💡

答案一:

#!/bin/bash
config_file="config.txt"

if [ -f "$config_file" ]; then
echo "配置文件存在"
else
echo "配置文件不存在"
fi

答案二:

#!/bin/bash
number=$1 # 假设第一个参数是数字

# 实际脚本中应添加检查 $1 是否为空或非数字
if [ $number -gt 0 ]; then
echo "正数"
elif [ $number -lt 0 ]; then
echo "负数"
else
echo "零"
fi

答案三:

#!/bin/bash
for fruit in apple banana cherry; do
echo "水果: $fruit"
done

答案四:

#!/bin/bash
sum=0
counter=1
while [ $counter -le 10 ]; do
sum=$((sum + counter))
counter=$((counter + 1))
done
echo "1 加到 10 的总和是: $sum" # 输出 55

答案五:
是的,它们在逻辑上是等价的 ✅。两者都是用于等待某个条件(文件存在)成立

答案六:

#!/bin/bash
for i in {1..20}; do
echo "当前数字: $i"
if [ $i -eq 13 ]; then
echo "遇到 13,停止循环!"
break # 跳出循环
fi
done
echo "循环结束。"

(或者用 C 风格 for 循环实现同样效果):

#!/bin/bash
for (( i=1; i<=20; i++ )); do
echo "当前数字: $i"
if [ $i -eq 13 ]; then
echo "遇到 13,停止循环!"
break
fi
done
echo "循环结束。"

答案七:

#!/bin/bash
echo "打印非 3 的倍数 (1-10):"
for i in {1..10}; do
if [ $((i % 3)) -eq 0 ]; then # 如果是 3 的倍数
continue # 跳过本次循环
fi
echo $i
done

(或者用 C 风格 for 循环实现):

#!/bin/bash
echo "打印非 3 的倍数 (1-10):"
for (( i=1; i<=10; i++ )); do
if [ $((i % 3)) -eq 0 ]; then
continue
fi
echo $i
done

答案八:

#!/bin/bash
command="start" # 假设 command 变量的值是 start

case $command in
start)
echo "启动服务"
;;
stop)
echo "停止服务"
;;
restart)
echo "重启服务"
;;
*)
echo "未知命令: $command"
;;
esac
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值