当前位置: 首页 > news >正文

Shell 循环实战:while 与 until 的趣味编程之旅

Shell 循环实战:while 与 until 的趣味编程之旅

1. 循环基础:当型和直到型

1.1 while 循环:条件成立就继续

bash

# 基本语法
while <条件表达式>
do指令...
done

形象记忆(某女生版):

bash

# 如果男朋友努力工作,就继续相处
while 男朋友努力工作
do继续相处
done

执行流程:先检查条件,成立就执行循环体,直到条件不成立为止。

在这里插入图片描述

1.2 until 循环:条件不成立才继续

bash

# 基本语法
until <条件表达式>
do指令...
done

形象记忆

bash

# 直到男朋友不努力工作,就不继续相处
until 男朋友不努力工作
do继续相处 
done

执行流程:先检查条件,不成立就执行循环体,直到条件成立为止。

在这里插入图片描述

2. 基础示例:从简单到有趣

示例1:倒数打印 5-1

while 版本

bash

#!/bin/bash
i=5
while ((i>0))
doecho $i((i--))  # i减1
done

until 版本

bash

#!/bin/bash
i=5
until ((i==0))  # 直到i等于0停止
doecho $i((i--))
done

示例2:计算1到100的和

bash

#!/bin/bash
i=1
sum=0
while ((i<=100))
do((sum+=i))  # 累加((i++))     # i加1
done
echo "1+2+3+...+99+100=$sum"

示例3:计算5的阶乘

bash

#!/bin/bash
i=1
sum=1
while ((i<=5))
do((sum*=i))  # 连乘((i++))
done
echo "5的阶乘为:$sum"

示例4:猴子吃桃问题

猴子每天吃一半加一个桃子,第10天只剩1个,问最初有多少桃子?

解法1:while 循环

bash

#!/bin/bash
today=1     # 第10天的桃子数
i=1         # 循环计数器while ((i<=9))  # 循环9次(第9天到第1天)
do# 计算上一天的桃子数:今天桃子数加1再乘以2lastday=$[(today+1)*2]today=${lastday}  # 更新为前一天的数量((i++))
done
echo "猴子第一天摘的桃子数量是:$today。"

解法2:函数递归(高级技巧)

bash

#!/bin/bash
function sum (){if [[ $1 = 1 ]];thenecho $1else# 递归调用:前一天的桃子数是(后一天+1)*2echo $[ ($(sum $[$1 -1]) + 1)*2 ]fi
}
echo "猴子第一天摘的桃子数量是:$(sum 10)。"

示例5:猜数字游戏

bash

#!/bin/bash
# 生成1-50的随机数
random_num=$[ RANDOM%50+1 ]
echo "${random_num}" >> /tmp/number  # 保存答案(临时)i=0  # 猜的次数计数
while true  # 无限循环
doread -p "猜一猜系统产生的50以内随机数是:" numif ((num>=1 && num<=50));then((i++))  # 增加猜测次数if [ $num -eq ${random_num} ];thenecho "恭喜你,第$i次猜对了!"rm -f /tmp/number  # 清理临时文件exit  # 游戏结束elseecho -n "第$i次猜测,加油。"# 给出提示:太大了还是太小了[ $num -gt ${random_num} ] && echo "太大了,往小猜。" || echo "太小了,往大猜。"fielseecho "请输入一个介于1-50之间的数字。"fi 
done

3. 后台运行与并发控制

3.1 后台运行脚本的方法

  1. 直接后台运行sh script.sh &
  2. 不挂断运行nohup sh script.sh &
  3. 会话保持:使用 screentmux 工具

3.2 控制后台任务的命令

  • &:后台运行
  • ctrl+c:停止当前任务
  • ctrl+z:暂停当前任务
  • bg:将任务放到后台运行
  • fg:将任务拉到前台运行
  • jobs:查看后台任务列表
  • kill %n:结束编号为n的后台任务

示例:让所有CPU满负荷工作

bash

#!/bin/bash
# 获取CPU核心数
cpu_count=$(lscpu|grep '^CPU(s)'|awk '{print $2}')
i=1while ((i<=${cpu_count}))
do{# 无限循环计算,消耗CPUwhile :do((1+1))done} &  # 放到后台运行((i++))
done

示例:控制并发数量(不超过CPU数)

bash

#!/bin/bash
# 获取CPU核心数
cpu_count=$(lscpu | awk '/^CPU\(s\):/ { print $2}')while true
do# 启动一个CPU负载任务bash cpu_load_script.sh &# 控制并发数量while truedojobs=$(jobs -l |wc -l)  # 当前后台任务数if [ $jobs -ge $cpu_count ];thensleep 3  # 如果任务数已达CPU数,等待3秒elsebreak    # 还有空余,退出等待循环fidone
done

使用wait等待后台任务完成

bash

#!/bin/bash
> /tmp/sleep  # 清空临时文件
i=1while [ $i -le 10 ]
do# 每个任务睡眠不同时间然后写入文件( sleep $i && echo "sleep $i" >> /tmp/sleep ) &((i++))
donewait  # 等待所有后台任务完成
cat /tmp/sleep  # 显示结果

4. 实战应用:系统监控与服务管理

示例1:每隔2秒输出系统负载

bash

#!/bin/bash
while true
douptime  # 显示系统负载sleep 2
done

示例2:SSHD服务监控与自动重启

while版本

bash

#!/bin/bash
while true
do # 检查sshd是否活跃systemctl is-active sshd.service &>/dev/nullif [ $? -ne 0 ];then echo "SSHD服务未运行,正在重启..."systemctl restart sshd.service &>/dev/nullfisleep 5  # 每5秒检查一次
done

until版本

bash

#!/bin/bash
until false  # 一直循环直到false(永远不会发生)
do systemctl is-active sshd.service &>/dev/nullif [ $? -ne 0 ];then systemctl restart sshd.service &>/dev/nullfisleep 5
done

示例3:网站可用性监控

bash

#!/bin/bashif [ $# -ne 1 ];thenecho "Usage: $0 url"exit 1
fiurl="$1"while true
do# 检查网站是否可访问(5秒超时)if curl -o /dev/null -s --connect-timeout 5 $url;thenecho "$(date): $url is ok."elseecho "$(date): $url is error."fisleep 3  # 每3秒检查一次
done

5. 高级实战:手机短信平台模拟

bash

#!/bin/bash# 初始化变量
money=0.5                    # 初始余额(0.5元)
msg_file=/tmp/message        # 消息存储文件
> $msg_file                  # 清空消息文件# 手机操作菜单
function print_menu () {cat << EOF
1. 查询余额
2. 发送消息
3. 充值
4. 退出
EOF
}# 检查输入是否为数字
function check_digit () {expr $1 + 1 &> /dev/null && return 0 || return 1
}# 显示余额
function check_money_all () {echo "余额为:$money 元。"
}# 检查余额是否足够发送一条消息(0.15元)
function check_money () {# 将元转换为分进行比较new_money=$(echo "$money*100"|bc|cut -d . -f1)if [ ${new_money} -lt 15 ];thenecho "余额不足,请充值。"return 1  # 余额不足elsereturn 0  # 余额充足fi
}# 充值功能
function chongzhi () {read -p "充值金额(单位:元):" chongzhi_moneywhile truedocheck_digit $chongzhi_moneyif [ $? -eq 0 ] && [ ${chongzhi_money} -ge 1 ];then# 更新余额money=$( echo "($money+${chongzhi_money})"|bc)echo "当前余额为:$money 元"return 0elseread -p "请输入有效金额(至少1元):" chongzhi_money fidone
}# 发送消息功能
function send_msg () {# 检查余额是否充足check_moneyif [ $? -eq 0 ];then  # 余额充足read -p "请输入消息内容:" messageecho "$message" >> ${msg_file}  # 保存消息# 扣除费用(0.15元)new_money=$(echo "scale=2;($money*100-15)" | bc |cut -d. -f1 )# 格式化工整的金额显示if [ ${new_money} -ge 100 ];thenmoney=$(echo "scale=2;${new_money}/100" | bc )elsemoney=0$(echo "scale=2;${new_money}/100" | bc )fiecho "消息已发送!当前余额为:$money 元"fi
}# 主程序
while true
doprint_menuechoread -p "请输入你的选择:" choiceclearcase $choice in1)check_money_all;;2)send_msg;;3)chongzhi;;4)echo "谢谢使用,再见!"exit;;*)echo "无效选择,请从1、2、3、4中选择。" ;;esacecho
done

6. 文件读取的四种方式

以读取 /etc/hosts 文件为例:

方式1:使用exec重定向

bash

#!/bin/bash
exec < /etc/hosts  # 将文件内容重定向到标准输入
while read line
doecho $line
done

方式2:使用管道

bash

#!/bin/bash
cat /etc/hosts | while read line
doecho $line
done

方式3:在循环结尾重定向

bash

#!/bin/bash
while read line
doecho $line
done < /etc/hosts  # 在done处重定向

方式4:设置分隔符并使用for循环

bash

#!/bin/bash
IFS=$'\n'  # 设置换行符为字段分隔符
for line in $(cat /etc/hosts)
doecho $line
done

7. 企业级实战:网络安全防护

示例1:防止Web服务的DDoS攻击

bash

#!/bin/bash
logfile=$1  # 日志文件作为参数while true
do# 分析日志:提取IP并统计访问次数awk '{print $1}' $logfile | grep -v "^$" | sort | uniq -c > /tmp/tmp.log# 处理统计结果exec < /tmp/tmp.logwhile read linedoip=$(echo $line | awk '{print $2}')      # 提取IPcount=$(echo $line | awk '{print $1}')   # 提取访问次数# 如果单IP访问超过500次且未被封禁if [ $count -gt 500 ] && [ $(iptables -L -n | grep "$ip" | wc -l) -lt 1 ];theniptables -I INPUT -s $ip -j DROP  # 封禁IPecho "$(date): $ip 已被封禁(访问次数: $count)" >> /tmp/droplist_$(date +%F).logfidonesleep 3600  # 每小时检查一次
done

示例2:监控网络连接数并封禁异常IP

bash

#!/bin/bash
while true
do# 获取已建立连接的IP及连接数ss -t | grep ESTAB | awk '{print $4}' | cut -d: -f1 | sort | uniq -c > /tmp/tmp.logexec < /tmp/tmp.logwhile read linedoip=$(echo $line | awk '{print $2}')count=$(echo $line | awk '{print $1}')# 如果单IP连接数超过100且未被封禁if [ $count -gt 100 ] && [ $(iptables -L -n | grep "$ip" | wc -l) -lt 1 ];theniptables -I INPUT -s $ip -j DROPecho "$(date): $ip 已被封禁(连接数: $count)" >> /tmp/droplist_$(date +%F).logfidonesleep 10  # 每10秒检查一次
done

8. 本章小结与使用场景

8.1 各循环结构的使用场景

  • while循环:最适合守护进程和需要持续运行的场景,频率低于1分钟的监控任务
  • until循环:与while类似,但条件判断逻辑相反
  • for循环(后续章节):最适合已知循环次数的常规处理
  • case语句:适合服务启动脚本中的多分支选择
  • if语句:最常用的条件判断结构

8.2 一句话应用场景

  • 条件判断:if 和条件表达式 [ ]

  • 固定次数循环:for

  • 守护进程/无限循环:while + sleep

  • 服务脚本选择:case

  • 代码复用:函数

    如果单IP连接数超过100且未被封禁

    if [ $count -gt 100 ] && [ (iptables−L−n∣grep"(iptables -L -n | grep "(iptablesLngrep"ip" | wc -l) -lt 1 ];then
    iptables -I INPUT -s ip−jDROPecho"ip -j DROPecho "ipjDROPecho"(date): $ip 已被封禁(连接数: KaTeX parse error: Expected group after '_' at position 25: …> /tmp/droplist_̲(date +%F).log
    fi
    done

    sleep 10 # 每10秒检查一次
    done


## 8. 本章小结与使用场景### 8.1 各循环结构的使用场景- **while循环**:最适合守护进程和需要持续运行的场景,频率低于1分钟的监控任务
- **until循环**:与while类似,但条件判断逻辑相反
- **for循环**(后续章节):最适合已知循环次数的常规处理
- **case语句**:适合服务启动脚本中的多分支选择
- **if语句**:最常用的条件判断结构### 8.2 一句话应用场景- 条件判断:`if` 和条件表达式 `[ ]`
- 固定次数循环:`for`
- 守护进程/无限循环:`while` + `sleep`
- 服务脚本选择:`case`
- 代码复用:函数希望这篇轻松易懂的教程帮助你掌握了while和until循环的用法!记得多动手实践,才能真正掌握这些技巧。
http://www.dtcms.com/a/348730.html

相关文章:

  • 【轨物交流】轨物科技亮相“智汇日照・杭电赋能”科技合作交流会,共谋产学研用新篇章
  • MOS的导通及应用
  • 6.2 el-menu
  • 20.13 ChatGLM3 QLoRA微调实战:3步实现高效低资源训练
  • 06 - spring security角色和权限设置
  • 虚拟机蓝屏问题排查与解决
  • 小工具推荐
  • 【数据结构】栈和队列——栈
  • 生成模型 | DDPM -> Imrpoved DDPM -> DDIM
  • LIANA | part2 results部分
  • QML Charts组件之坐标轴示例
  • LangGraph 与 MCP 模型上下文协议简介与演示
  • 教育系统搭建攻略:线上知识付费与线下消课排课全解析
  • 【Java开发日记】我们来讲一讲 Channel 和 FileChannel
  • Polkadot - JAM
  • 美股期权历史市场数据波动特性分析
  • 【中文教材】14. 汇率计算
  • 人工智能-python-深度学习-tensor基操
  • 数学建模(摸索中……)
  • CUDA安装,pytorch库安装
  • 如何实现模版引擎
  • Shell 学习笔记 - Shell 三剑客篇
  • unity热更新总结
  • 【如何使用Redis实现分布式锁详解讲解】
  • [快乐数](哈希表)
  • 解决编译osgEarth中winsocket2.h找不到头文件问题
  • 基于Spark的热门旅游景点数据分析系统的设计-django+spider
  • Spring Boot测试陷阱:失败测试为何“传染”其他用例?
  • 【追涨抄底关注】副图指标 紫色主力线上行表明资金介入明显 配合价格突破时可靠性更高
  • deepseek连接solidworks设计一台非标设备 (part1)