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

【网络运维】Shell 脚本编程:while 循环与 until 循环

Shell 脚本编程:while 循环与 until 循环

循环结构简介

循环语句是 Shell 脚本中用于重复执行一条或一组指令的重要工具,直到满足特定条件时停止执行。Shell 脚本中常见的循环语句包括 while、until、for 和 select。本文将重点介绍 while 和 until 两种循环结构,并通过丰富的示例展示其实际应用场景。

while 循环与 until 循环语法解析

while 循环语法

while 循环属于“当型”循环结构,其基本语法格式为:

while <条件表达式>
do指令...
done

执行逻辑

  • 首先判断条件表达式是否成立
  • 如果成立,则执行循环体内的指令
  • 每次执行到 done 时重新判断条件表达式
  • 直到条件不成立时退出循环

until 循环语法

until 循环属于"直到型"循环结构,其基本语法格式为:

until <条件表达式>
do指令...
done

执行逻辑

  • 当条件表达式不成立时执行循环体
  • 直到条件表达式成立时终止循环

基础应用示例

示例1:竖向打印数字

while 实现方式

#!/bin/bash
i=5
while ((i>0))  # 当i大于0时执行循环
doecho $i     # 打印当前i值((i--))     # i自减1
done

until 实现方式

#!/bin/bash
i=5
until ((i==0))  # 直到i等于0时停止循环
doecho $i       # 打印当前i值((i--))       # i自减1
done

示例2:计算1-100的累加和

#!/bin/bash
i=1
sum=0
while ((i<=100))    # 当i小于等于100时执行循环
do((sum+=i))        # 累加i到sum变量# let sum=sum+i   # 另一种累加方式((i++))           # i自增1# let i++         # 另一种自增方式
done
echo "1+2+3+...+99+100=$sum"  # 输出结果

示例3:计算5的阶乘

#!/bin/bash
i=1
sum=1
while ((i<=5))    # 循环5次
do((sum*=i))      # 累乘计算阶乘((i++))         # i自增1
done
echo "5的阶乘为:$sum"  # 输出结果

示例4:猴子吃桃问题

问题描述

  • 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个
  • 第二天早上又将第一天剩下的桃子吃掉一半,又多吃了一个
  • 以后每天早上都吃了前一天剩下的一半零一个
  • 到第10天早上想再吃时,发现只剩下一个桃子了

问:猴子第一天摘了多少个桃子?

while循环解法

#!/bin/bash
# 当天桃子数量,第10天为1
today=1
# 前一天桃子数量
lastday=0
# 只需要迭代9次(从第10天倒推回第1天)
i=1
while ((i<=9))
do# 计算上一天桃子数量:today = (lastday/2) - 1 → lastday = (today+1)*2lastday=$[(today+1)*2]# 把上一天的数量当作今天的数量,继续向前推算today=${lastday}((i++))
done
echo "猴子第一天摘的桃子数量是:$today。"

函数递归解法

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

示例5:猜数字游戏

#!/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

脚本后台运行与管理

后台运行方法

在实际工作中,可能需要让脚本在后台持续运行:

  1. 使用 & 符号sh /server/scripts/while_01.sh &
  2. 使用 nohup 命令nohup /server/scripts/uptime.sh &
  3. 使用 screen 会话screen -S session_name 然后执行脚本

进程管理命令

  • sh whilel.sh &:后台运行脚本
  • ctl+c:停止当前任务
  • ctl+z:暂停当前任务
  • bg:将任务放到后台运行
  • fg:将任务调到前台运行
  • jobs:查看当前任务
  • kill:终止指定任务

并发控制示例

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

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

注意事项

  • { command1; command2; ... } & 可以将多个命令放到后台运行
  • {} 内部两侧需要有空格
  • 最后一个命令后需要有分号

使用wait等待后台任务完成

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

实战应用

示例1:监控系统负载

#!/bin/bash
while true  # 无限循环
douptime    # 显示系统负载sleep 2   # 休眠2秒
done

后台运行并记录日志

#!/bin/bash
while true
douptime >> /tmp/loadaverage.log  # 追加到日志文件sleep 2
done# 后台运行
bash while2.sh &

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

while格式

#!/bin/bash
while true
do # 检查sshd服务是否活跃systemctl is-active sshd.service &>/dev/nullif [ $? -ne 0 ];then  # 如果服务不活跃systemctl restart sshd.service  &>/dev/null  # 重启服务fisleep 5  # 每5秒检查一次
done

until格式

#!/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:网站可用性监控

#!/bin/bash# 参数检查
if [ $# -ne 1 ];thenecho "Usage: $0 url"exit 1
fiurl="$1"while true
do# 使用curl检查网站可用性if curl -o /dev/null -s --connect-timeout 5 $url;thenecho "$(date): $url is ok."  # 添加时间戳elseecho "$(date): $url is error."fisleep 3  # 每3秒检查一次
done

示例4:简易短信平台模拟

#!/bin/bash# 初始化变量
money=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 ];thenmoney=$( echo "($money+${chongzhi_money})"|bc)  # 使用bc进行浮点计算echo "当前余额为:$money 元"return 0elseread -p "重新输入充值金额(至少1元):" chongzhi_money fidone
}# 发送消息函数
function send_msg () {check_money  # 检查余额if [ $? -eq 0 ];then  # 余额充足read -p "请输入消息内容:" messageecho "$(date): $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

while循环读取文件的四种方式

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

方式1:使用exec重定向

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

方式2:使用管道

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

方式3:使用输入重定向

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

方式4:设置IFS分隔符

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

实战案例

案例1:防止DDoS攻击 - Web日志分析

#!/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}')  # 提取访问次数# 如果访问次数超过500且不在防火墙黑名单中if [ $count -gt 500 ] && [ $(iptables -L -n | grep "$ip" | wc -l) -lt 1 ];theniptables -I INPUT -s $ip -j DROP  # 封禁IPecho "$(date): $ip is dropped (PV: $count)" >> /tmp/droplist_$(date +%F).logfidonesleep 3600  # 每小时检查一次
done

案例2:防止DDoS攻击 - 网络连接数监控

#!/bin/bash
while true
do# 统计ESTABLISHED状态的连接并按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 is dropped (连接数: $count)" >> /tmp/droplist_$(date +%F).logfidonesleep 10  # 每10秒检查一次
done

总结

  1. while循环特点

    • 擅长执行守护进程和持续运行的应用
    • 适合处理频率小于1分钟的循环任务
    • 多数while循环可用for循环或cron定时任务替代
  2. 各语句使用场景

    • 条件表达式:简短条件判断(文件存在、字符串非空等)
    • if语句:不同值数量较少的条件判断
    • for循环:常规循环处理的首选
    • while循环:守护进程、无限循环(需配合sleep控制频率)
    • case语句:服务启动脚本、固定规则字符串处理
    • select语句:菜单打印(较少使用,通常用here文档替代)
  3. 函数的作用

    • 使代码逻辑更加清晰
    • 减少重复代码开发
    • 提高代码可维护性
http://www.dtcms.com/a/348090.html

相关文章:

  • Python自学笔记11 Numpy的索引和切片
  • Shell脚本-expect
  • VirtualBox安装openEuler24.03
  • 【C++】函数返回方式详解:传值、传引用与传地址
  • 校园跑腿小程序源码 | 跑腿便利店小程序 含搭建教程
  • 如何在 Ubuntu 上安装和配置 Samba ?
  • 2025年渗透测试面试题总结-30(题目+回答)
  • Java 20 新特性及具体应用
  • Cisdem Video Converter for mac 优秀的视频格式转换工具
  • 夜间跌倒检测响应速度↑150%!陌讯多模态骨架追踪算法在智慧养老院的落地实践
  • 埃氏筛|树dfs|差分计数
  • JVM OOM问题排查与解决思路
  • Meta AI 剧变:汪滔挥刀重组,Llama 开源路线告急,超级智能梦碎还是重生?
  • 96、23种设计模式之原型模式(5/23)
  • STM32 USB 之大坑
  • ubuntu中网卡的 IP 及网关配置设置为永久生效
  • Ubuntu24.04环境下causal_conv1d和mamba_ssm安装
  • 嵌入式八股文面试题总结(QT、RTOS、Linux、ARM、C/C++)(持续更新)
  • QT-布局管理器
  • 音视频面试题集锦第 32 期
  • C语言指针5
  • 使用虚幻引擎5(UE5)开发类似《原神》的开放世界游戏:从技术架构到实践指南
  • LeetCode-542. 01 矩阵
  • (LeetCode 每日一题) 1493. 删掉一个元素以后全为 1 的最长子数组 (双指针)
  • 03-鸿蒙架构与编程模型
  • ChainVault:重塑亚洲黄金交易基建,引领RWA金融新浪潮
  • Java 22 新特性及具体应用
  • week4-[字符数组]英语作文
  • Games101 作业1 旋转与投影
  • 量子链(Qtum)分布式治理协议