shell-循环控制-3
Linux Shell 脚本
编程逻辑与控制结构
- 编程逻辑处理
- 顺序执行
- 选择执行
- 循环执行
- 将某代码段重复运行多次
- 重复运行多少次
- 有进入条件和退出条件
- shell中控制流结构
- if … then … else … fi
- case 语句 ;; esac
- for 循环
- until 循环
- while 循环
- break 控制
- continue 控制
if … then … else … fi
-
示例
# 用中文描述, 如果if 1大于2, 那就打印echo 对, 否则就else 打印 不对的; fi结束 if 条件; then 语句; else 语句; fi [root@localhost opt]# if [[ 1 > 2 ]]; then echo "对"; else echo "不对"; fi 不对# 也可以用这种方式 Shell 条件逻辑 [root@localhost opt]# [[ 222 > 333 ]] && echo "对" || echo "不对" 不对
case
-
语法
# case 变量名 in 从上下下看每个 变量名 做一下比较,如果匹配就执行这个逻辑 case "$变量名" in "模式1") # 当变量值匹配“模式1”时执行的命令 命令1 命令2 ;; # 结束当前分支(必须用两个分号) "模式2" | "模式3") # 用 | 表示“模式2或模式3都匹配” # 当变量值匹配模式2或模式3时执行的命令 命令3 ;; *) # 所有模式都不匹配时(默认情况,类似 else) # 默认执行的命令 echo "没有匹配的选项" ;; esac # 结束 case 语句(case 的反写) -
示例
[root@localhost opt]# cat -n case.sh 1 #!/usr/bin/env bash2 #3 case $1 in 4 get1)5 echo "第一" ;;6 get2)7 echo "第二" ;;8 *)9 echo "没有这个变量" ;;10 esac [root@localhost opt]# bash case.sh get 没有这个变量 [root@localhost opt]# bash case.sh get1 第一
for
-
语法:
for 变量名 in 列表; do 循环体 ; done-
格式
-
双小括号方法,即((…))格式,也可以用于算术运算
-
双小括号方法也可以使bash Shell实现C语言风格的变量操作
i=10 ((i++)) -
for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do循环体 done -
控制变量初始化:仅在运行到循环代码段时执行一次
-
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
-
-
-
列表
- 直接给出列表
- 整数列表
- {start…end} 如:
for i in {1..10} - $(seq [start [step]] end) 如
for i in seq 1 10 - for (( i=0;i<=num;i++))
- {start…end} 如:
- 返回列表命令
- $(COMMAND)
- 整数列表
- 直接给出列表
-
示例
-
for列表的几种用法
[root@localhost opt]# for i in {1..10};do echo $i;done# 从1 开始打印1-10 [root@localhost opt]# for u in `seq 1 1 10`;do echo $u;done # 从2 开始打印1-10 [root@localhost opt]# for u in `seq 2 1 10`;do echo $u;done # 从1 开始每次加2, 就是13579 [root@localhost opt]# for u in `seq 1 2 10`;do echo $u;done[root@localhost opt]# for ((i=0;i<=10;i++ ));do echo $i;done -
添加10个用户user1-user10,密码为8位随机字符
echo $RANDOM|/usr/bin/md5sum | /usr/bin/cut -c 2-9 # 随机生成密码for i in {1..10};dopass=`echo $RANDOM|/usr/bin/md5sum | /usr/bin/cut -c 2-9`count=`cat /etc/passwd | cut -f1 -d":" | grep "user1$" -c`if [ $count -eq 0 ];thenuseradd user$iecho $pass | passwd --stdin user$i &>/dev/nullecho "user$i password: $pass" >> ./user.txtelseecho 'user$i 已存在' >> /.user.txtfi done -
编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
read -p "请输入整数: " num sum=0 for i in `seq 1 1 $num`;do#sum=$[$sum+$i]sum=$(($sum+$i)) done echo $sum -
计算100以内所有能被3整除的整数之和
sum=0 for i in {1..100};do[ $(($i%3)) -eq 0 ] && sum=$(($sum+$i)) done echo $sum -
打印九九乘法表
for i in `seq 1 9`;dofor u in `seq 1 9`;do[ $u -le $i ] && echo -e "$i*$u=$(($i*$u))\t\c"doneecho "" done
-
until
是 Shell 脚本中与
while互补的循环结构,当条件为假时执行循环,直到条件变为真。以下是核心用法和示例
-
语法
until [ 条件测试 ]; do # 循环体命令 done- 先检查条件,若条件为 假(非零退出状态),则执行循环体。
- 每次循环后重新检查条件,一旦条件为 真(退出状态为 0),循环终止。
-
示例
-
等待文件生成
until [ -f /tmp/ready.flag ]; do echo "等待文件生成..." sleep 5 done echo "文件已就绪!" # 说明:每 5 秒检查一次文件 /tmp/ready.flag ,直到文件存在后退出循环。 -
服务启动检测
until systemctl is-active nginx >/dev/null 2>&1; do echo "Nginx 未运行,尝试启动..." systemctl start nginx sleep 3 done echo "Nginx 已启动!" # 说明:循环尝试启动 Nginx,直到服务状态变为 active。 -
超时控制
timeout=10 count=0 until [ $count -ge $timeout ]; do ping -c1 example.com && break echo "第 $count 次尝试..." ((count++)) sleep 1 done # 说明:10 秒内尝试 ping 服务器,成功则提前退出,超时后终止。 -
用户输入验证
until $ ]]; do read -p "确认操作?(Y/N): " input done # 说明:强制用户输入 Y/N 或 y/n,否则重复提示。
-
while
-
语法
while [ 条件表达式 ]; do # 循环体(命令序列) done- 每次循环前判断,为
true则执行循环体,为false则退出循环 - 条件可使用
test命令([ ])、双括号(( ))(算术判断)或命令返回值(0 为 true,非 0 为 false)。
- 每次循环前判断,为
-
冒号说明
**冒号:**与true 语句不执行任何实际的处理动作,但可用于返回一个出口状态为0 的测试条件。这两个语句常用于While 循环结构的元限循环测试条件,我们在脚本中经常会见到这样的使用
while : # 这表示是一个无限循环的过程,所以使用的时候要特别注意,不要形成了死循环,所以一般会定义一个sleep 时间,可以实现秒级别的cron 任务,其语法格式为:# ; 分号允许在一行放多个命令 while :;do echo 'yep'; sleep 3;done # 实例了一个无限循环,每隔3秒打印一次yep -
示例
-
使用
[ ]判断(字符串/文件属性等)count=1 while [ $count -le 5 ]; do # 当 count ≤ 5 时循环 echo "第 $count 次循环" count=$((count + 1)) # 计数器自增(也可用 count=$[count+1]) done -
使用
(( ))算术判断(更简洁的数字比较)i=3 while ((i > 0)); do # 当 i > 0 时循环 echo "倒计时: $i" ((i--)) # i 自减 1 done echo "结束!" 倒计时: 3 倒计时: 2 倒计时: 1 结束! -
求100以内所有正奇数之和
o=0 j=0 i=0 while [ $i -lt 101 ];do[ $(($i%2)) -eq 0 ] && o=$(($o+$i)) || j=$(($j+$i))i=$(($i+1)) doneecho "偶数: " $o echo "奇数: " $j -
遍历文件内容(逐行读取)
# 读取 file.txt 内容,打印行号和内容 line_num=1 while read line; do echo "第 $line_num 行: $line" line_num=$((line_num + 1)) done < file.txt # 通过重定向输入文件 # 说明:< file.txt 将文件内容作为 read 命令的输入,每次循环读取一行到变量 line。 -
遍历命令输出(管道传递)
# 遍历当前目录下的 .txt 文件(每行一个文件名) ls *.txt | while read filename; do echo "找到文件: $filename" # 可添加处理命令,如 cat $filename、mv $filename ./backup/ 等 done -
判断主机是否在线
# 编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少 read -p "请输入网段" num net=`echo $num | cut -d'.' -f1-3` up=0 down=0 while true;dofor i in `seq 1 3`;doip=$net.$iping -c 1 -w 1 $ip &>/dev/nullif [ $? -eq 0 ];then echo "$ip 在线" up=$(($up+1))elseecho "$ip 不在线" down=$(($down+1))fidoneecho "在线主机$up, 不在线主线$down" break done -
打印九九乘法表
i=1 while [ $i -lt 10 ];dofor u in `seq 1 9`;do[ $u -lt $i ] && echo -e "$u*$i=$(($i*$u))\t\c"done echo "" i=$(($i+1)) done -
查找ip
#!/bin/bash # while true;do# 读取用户输入read -p "请输入一个IPv4地址: " ip_address# 定义IPv4地址的正则表达式ipv4_regex='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'# 使用正则表达式判断输入是否为IPv4地址[[ $ip_address =~ $ipv4_regex ]] && break || echo "输入的地址不是一个有效的IPv4地址, 请重新输入" donesed -i "/^.*[[:space:]]unicast_peer /{n;s/^\(.*[[:space:]]\)\([0-9].*\)\(#.*\)/\1${ip_address}\1\3/}" test.tx
-
continue
-
说明
- 无限循环(条件始终为 true)
- 需配合
break手动退出循环,常用于菜单交互或持续监听。 - continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为: 第1层
-
示例
-
示例1:打印1-10,但跳过偶数
#!/bin/bash i=1 while [ $i -le 10 ]; do if [ $((i % 2)) -eq 0 ]; then # 如果i是偶数 i=$((i + 1)) # 先自增i(避免死循环) continue # 跳过当前循环剩余部分,直接进入下一次循环 fi echo "当前数字:$i" # 只打印奇数 i=$((i + 1)) done # 打印 1,3,5,7,9 # 当 i 为偶数时,continue 会跳过 echo 语句,直接进入下一次循环判断。 -
读取文件内容,跳过空行和注释行(以
#开头)# 文本 test.txt hello # 这是注释行 world # 另一个注释 linux #!/bin/bash while IFS= read -r line; do # 逐行读取文件 # 跳过空行或注释行 if [ -z "$line" ] || [[ "$line" == \#* ]]; then continue # 跳过当前行,读取下一行 fi echo "有效内容:$line" done < test.txt # 从文件test.txt 读取输入 # IFS= read -r line 用于完整读取一行(包括空格)。 # -z "$line" 判断空行,[[ "$line" == \#* ]] 判断以 # 开头的行,满足其一则 continue 跳过。 -
要求用户输入1-5之间的数字,否则重新输入
#!/bin/bash echo "请输入1-5之间的数字:" while true; do # 无限循环,直到输入有效 read -r num # 判断是否为数字,且在1-5之间 if ! [[ "$num" =~ ^[0-9]+$ ]] || [ "$num" -lt 1 ] || [ "$num" -gt 5 ]; then echo "输入无效!请重新输入(1-5):" continue # 跳过剩余部分,重新读取输入 fi echo "你输入的有效数字是:$num" break # 输入有效,退出循环 done
while true; do # true 始终返回 0(条件为真) echo "输入 'q' 退出循环" read input if [ "$input" = "q" ]; then break # 输入 q 时退出循环 fi echo "你输入了: $input" done -
break
-
语法:用于立即终止当前循环并跳出循环体,通常配合条件判断使用
-
示例
-
循环打印数字,当数字等于
5时终止循环。#!/bin/bash i=1 while true; do # 无限循环(条件恒为真) echo "当前数字: $i" if [ $i -eq 5 ]; then # 当 i=5 时 break # 跳出循环 fi i=$((i + 1)) # i 自增 1 done echo "循环结束" -
循环读取用户输入,输入
q时退出。#!/bin/bash while true; do read -p "请输入内容(输入 q 退出): " input if [ "$input" = "q" ]; then # 输入为 "q" 时 echo "收到退出指令,程序结束" break # 跳出循环 fi echo "你输入的是: $input" done -
遍历目录下文件,找到
target.txt时停止搜索。#!/bin/bash file_list=("a.txt" "b.txt" "target.txt" "c.txt") # 模拟文件列表 index=0 while [ $index -lt ${#file_list[@]} ]; do # 遍历数组 current_file=${file_list[$index]} echo "正在检查: $current_file" if [ "$current_file" = "target.txt" ]; then # 找到目标文件 echo "找到目标文件: $current_file,退出搜索" break # 跳出循环 fi index=$((index + 1)) done -
逐行读取文件内容,遇到空行时停止读取。
data.txt 第一行 第二行 第四行 # 空行后的内容 #!/bin/bash while IFS= read -r line; do # 逐行读取文件 if [ -z "$line" ]; then # 判断行是否为空(-z 表示字符串长度为 0) echo "遇到空行,停止读取" break # 跳出循环 fi echo "读取到: $line" done < data.txt # 从文件 data.txt 读取输入 ### 打印 读取到: 第一行 读取到: 第二行 遇到空行,停止读取
-
-
总结
while true可创建无限循环,需通过break手动控制退出。break仅跳出当前最内层循环(嵌套循环中需注意层级)。- 通常与
if条件判断结合,实现“满足特定条件时终止循环”的逻辑。
