shell 编程之循环语句

news2025/4/21 2:44:09

目录

一、for 循环语句

二、while 循环语句

三、until 循环语句

四、总结扩展

1. 循环对比

2. 调试技巧

3. 易混淆点解析

4. 进阶技巧


 

 

 

 

一、for 循环语句

1. 基础概念

含义

用于 遍历一个已知的列表,逐个执行同一组命令

核心作用

对一组固定或可枚举的数据(如文件列表、数字序列)进行重复操作。

结构:

for 变量 in 取值列表  
do  
    命令组  
done  

2. 示例

根据姓名列表批量添加用户

1.准备测试文件(user_list.txt)

2.添加编辑脚本

#!/bin/bash  

# 定义用户列表文件路径  
USER_LIST="/root/user_list.txt"  

# 检查文件是否存在  
if [ ! -f "$USER_LIST" ]; then  
    echo "错误:用户列表文件 $USER_LIST 不存在!"  
    exit 1  
fi  

# 使用 for 循环遍历文件中的用户名  
for username in $(cat "$USER_LIST"); do  
    # 跳过空行和注释行(以 # 开头)  
    if [[ -z "$username" || "$username" == \#* ]]; then  
        continue  
    fi  

    # 检查用户是否已存在  
    if id "$username" &> /dev/null; then  
        echo " 用户 $username 已存在,跳过..."  
    else  
         # 创建用户并设置家目录  
         useradd -m "$username"  
         # 设置初始密码(示例密码:123456)  
         echo "123456" | passwd --stdin  $username  &>/dev/null                          
    ###stdin : 标准输入 ,默认用键盘输入
         echo "用户 $username 创建成功!"  
    fi  
done  

echo "所有用户处理完成!"  

批量重启服务

#!/bin/bash
# 检查是否以 root 用户身份运行
if [ "$(id -u)" -ne 0 ]; then    
echo "请以 root 用户身份运行此脚本。"    
exit 1
fi
# 定义要重启的服务列表
services=("nginx" "mysql" "redis")
log_file="/var/log/service_restart.log"
# for 循环:批量重启服务
for service in "${services[@]}"; do    
# 检查服务是否正在运行    
if systemctl is-active --quiet $service; then        
echo "正在重启 $service 服务..."
        systemctl restart $service        
if [ $? -eq 0 ]; then            
echo "$service 服务重启成功。"        
else            
echo "$service 服务重启失败。" | tee -a $log_file
            systemctl status $service >> $log_file 2>&1            
echo "---------------------" >> $log_file        
fi    
else        
echo "$service 服务未运行,无需重启。"    
fi
done

3. 注意事项

  • 列表元素包含空格时需加引号:for item in "file 1" "file 2"

  • 使用$@遍历脚本参数:for param in "$@"


二、while 循环语句

1. 基础概念

含义:

当 条件测试结果为真(true)时,重复执行循环体,直到条件变为假(false)。

核心作用

处理不确定循环次数的场景(如持续读取输入、等待某个状态变化)。

结构:

while [ 条件测试 ]  
do  
    命令组  
done

2. 示例

批量添加规律编号的用户

#!/bin/bash  

PREFIX="stu"
#定义整数变量值为1
i=1

#设置密码为123456的批量用户
while [ $i -le 20 ]
do           
   useradd ${PREFIX}$i
   echo "123456" | passwd --stdin ${PREFIX}$i  &> /dev/null
   let i++    
    
done 
echo "所有用户处理完成!"  

持续监控磁盘使用率

#!/bin/bash
# 设定磁盘使用率阈值
threshold=80
# 日志文件路径
log_file="/var/log/disk_usage.log"

# while 循环:持续监控磁盘使用率
while true; do
    usage=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
    if [ $usage -gt $threshold ]; then
        timestamp=$(date '+%Y-%m-%d %H:%M:%S')
        message="$timestamp - 磁盘使用率超过 $threshold%,当前使用率为 $usage%。"
        echo "$message" | tee -a $log_file        
        # 可以添加发送邮件或者其他告警逻辑
    fi
    sleep 3600  # 每小时检查一次
done    

3. 注意事项

  • 避免死循环:若条件永远为真(如 while true),需手动退出(break)

  • 管道输入会创建子shell:echo "文本" | while read(子shell变量不传递到主进程)


三、until 循环语句

1. 基础概念

含义

当 条件测试结果为假(false)时,重复执行循环体,直到条件变为真(true)。

核心作用

与 while 逻辑相反,适用于需要“等待某个条件达成”的场景。

结构:

until [ 条件测试 ]          # 条件为假时执行  
do  
    命令组  
done 

2. 示例

指定用户发送在线消息

#!/bin/bash
# 检查参数数量是否足够
if [ $# -lt 2 ]; then
    echo "Usage: $0 <username1> <username2> ... <message>"
    exit 0
fi

# 提取消息,消息为最后一个参数
message="${!#}"

# 遍历除最后一个参数外的所有用户名
for username in "${@:1:$#-1}"; do
    # 检查用户是否为系统内用户
    if ! grep -q "^$username:" /etc/passwd; then
        echo "$(date +'%Y-%m-%d %H:%M:%S') - $username is not a valid user on this system."
        continue
    fi

    # 持续检查用户是否登录
    while ! who | grep -q "$username"; do
        echo "$(date +'%Y-%m-%d %H:%M:%S') - $username is not logged on. Waiting for the user to log in."
        sleep 60
    done

    # 检查用户是否允许接收消息
    if ! mesg -c | grep -q "is y"; then
        echo "$(date +'%Y-%m-%d %H:%M:%S') - $username has disabled message reception."
        continue
    fi

    # 用户已登录,发送消息
    echo "$(date +'%Y-%m-%d %H:%M:%S') - Sending message to $username..."
    write "$username" <<EOF
$message
EOF
    if [ $? -ne 0 ]; then
        echo "$(date +'%Y-%m-%d %H:%M:%S') - Failed to send message to $username."
    fi
done

持续尝试连接数据库,直至连接成功

#!/bin/bash
# 数据库连接信息
host="localhost"
port="3306"
user="root"
password="password"

# until 循环:持续尝试连接数据库直到成功
until mysql -h $host -P $port -u $user -p$password -e "SELECT 1" &> /dev/null; do
    echo "无法连接到数据库,等待 10 秒后重试..."
    sleep 10
done
echo "成功连接到数据库。"    

3. 特点

  • while逻辑相反:条件为时持续执行

  • 适合「等待型」场景(如检测服务就绪)

四、总结扩展

1. 循环对比

循环类型执行逻辑典型场景
for遍历列表中的每个元素处理文件、已知范围的数值迭代
while条件为真时执行读取输入流、条件动态变化的场景
until条件为假时执行等待某条件满足(如服务启动)

2. 调试技巧

#!/bin/bash -x  # 开启调试模式查看循环执行细节  
for file in *  
do  
    : # 空语句用于占位调试  
done  

3. 易混淆点解析

  • while vs until

    • while:条件为真时执行 → “只要...就继续”

    • until:条件为假时执行 → “直到...才停止”

  • for vs while

    • for 关注 遍历数据while 关注 动态条件

4. 进阶技巧

  • 嵌套循环

    for i in {1..3}  
    do  
      while [ $j -lt 2 ]  
      do  
          echo "$i-$j"  
          ((j++))  
      done  
    done  
  • 循环控制

    • break:立即退出循环。

    • continue:跳过当前迭代,进入下一轮。

  • 性能优化

    • 避免在循环内重复执行相同命令(如 ls),优先缓存结果。

    • 使用 & 后台执行耗时任务(需权衡并发控制)

    • 避免在循环内频繁调用grep/awk等外部命令

    • 大数据处理优先使用管道和xargs

    • 删除旧日志:

      #!/bin/bash
      # 清理 30 天前的日志文件(处理特殊字符)
      LOG_DIR="/var/log/app"
      DAYS=30
      
      find "$LOG_DIR" -type f -name "*.log" -mtime +$DAYS -print0 | while IFS= read -r -d '' file; do
          echo "删除旧日志: $file"
          rm -f "$file"
      done

      注释说明

-mtime +30:匹配修改时间超过 30 天的文件

-print0 + read -d '':安全处理含空格/换行符的文件名

  • 避免频繁启动子进程

    # 低效写法:每次循环调用一次 `date`  
    for i in {1..100}; do  
        current_time=$(date)  
        echo "$current_time"  
    done  
    
    # 高效写法:预先获取时间  
    current_time=$(date)  
    for i in {1..100}; do  
        echo "$current_time"  
    done  

    总结速查表

    场景推荐循环关键技巧
    遍历文件列表for + 引号包裹变量处理空格:find + while read -r
    动态读取输入/条件变化while用 break/continue 控制流程
    等待条件达成(如超时)until结合 sleep 避免 CPU 占用过高
    高性能批量处理xargs/parallel并行加速,减少子进程开销
    无限循环while true确保有退出条件(如 Ctrl+C 捕获信号)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10【模块学习】LCD1602(二):6路温度显示+实时时钟

项目&#xff1a;6路温度显示实时时钟 1、6路温度显示①TempMenu.c文件的代码②TempMenu.h文件的代码③main.c文件的代码④Timer.c文件的代码⑤Delay.c文件的代码⑥Key.c文件的代码 2、实时时钟显示①BeiJingTime.c文件的代码②BeiJingTime.h文件的代码③main.c文件的代码如下④…

PDF处理控件Aspose.PDF指南:使用 C# 从 PDF 文档中删除页面

需要从 PDF 文档中删除特定页面&#xff1f;本快速指南将向您展示如何仅用几行代码删除不需要的页面。无论您是清理报告、跳过空白页&#xff0c;还是在共享前自定义文档&#xff0c;C# 都能让 PDF 操作变得简单高效。学习如何以编程方式从 PDF 文档中选择和删除特定页面&#…

如何在不同版本的 Elasticsearch 之间以及集群之间迁移数据

作者&#xff1a;来自 Elastic Kofi Bartlett 当你想要升级一个 Elasticsearch 集群时&#xff0c;有时候创建一个新的独立集群并将数据从旧集群迁移到新集群会更容易一些。这让用户能够在不冒任何停机或数据丢失风险的情况下&#xff0c;在新集群上使用所有应用程序测试其所有…

Day08【基于预训练模型分词器实现交互型文本匹配】

基于预训练模型分词器实现交互型文本匹配 目标数据准备参数配置数据处理模型构建主程序测试与评估总结 目标 本文基于预训练模型bert分词器BertTokenizer&#xff0c;将输入的文本以文本对的形式&#xff0c;送入到分词器中得到文本对的词嵌入向量&#xff0c;之后经过若干网络…

npm和npx的作用和区别

npx 和 npm 是 Node.js 生态系统中两个常用的工具&#xff0c;它们有不同的作用和使用场景。 1. npm&#xff08;Node Package Manager&#xff09; 作用&#xff1a; npm 是 Node.js 的包管理工具&#xff0c;主要用于&#xff1a; 安装、卸载、更新项目依赖&#xff08;包&a…

C++学习之金融类安全传输平台项目git

目录 1.知识点概述 2.版本控制工具作用 3.git和SVN 4.git介绍 5.git安装 6.工作区 暂存区 版本库概念 7.本地文件添加到暂存区和提交到版本库 8.文件的修改和还原 9.查看提交的历史版本信息 10.版本差异比较 11.删除文件 12.本地版本管理设置忽略目录 13.远程git仓…

CCF CSP 第36次(2024.12)(1_移动_C++)

CCF CSP 第36次&#xff08;2024.12&#xff09;&#xff08;1_移动_C&#xff09; 解题思路&#xff1a;思路一&#xff1a; 代码实现代码实现&#xff08;思路一&#xff09;&#xff1a; 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 原题链接 解题思路&…

7.thinkphp的路由

一&#xff0e;路由简介 1. 路由的作用就是让URL地址更加的规范和优雅&#xff0c;或者说更加简洁&#xff1b; 2. 设置路由对URL的检测、验证等一系列操作提供了极大的便利性&#xff1b; 3. 路由是默认开启的&#xff0c;如果想要关闭路由&#xff0c;在config/app.php配置…

(五)机器学习---决策树和随机森林

在分类问题中还有一个常用算法&#xff1a;就是决策树。本文将会对决策树和随机森林进行介绍。 目录 一.决策树的基本原理 &#xff08;1&#xff09;决策树 &#xff08;2&#xff09;决策树的构建过程 &#xff08;3&#xff09;决策树特征选择 &#xff08;4&#xff0…

【项目管理】第16章 项目采购管理-- 知识点整理

项目管理-相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 &#xff08;一&#xff09;知识总览 项目管理知识域 知识点&#xff1a; &#xff08;项目管理概论、立项管理、十大知识域、配置与变更管理、绩效域&#xff09; 对应&…

从图像“看出动作”

&#x1f4d8; 第一部分&#xff1a;运动估计&#xff08;Motion Estimation&#xff09; &#x1f9e0; 什么是运动估计&#xff1f; 简单说&#xff1a; &#x1f449; 给你一段视频&#xff0c;计算机要“看懂”里面什么东西动了、往哪动了、有多快。 比如&#xff1a; 一…

鸿蒙案例---生肖抽卡

案例源码&#xff1a; Zodiac_cards: 鸿蒙生肖抽奖卡片 效果演示 初始布局 1. Badge 角标组件 此处为语雀内容卡片&#xff0c;点击链接查看&#xff1a;https://www.yuque.com/kevin-nzthp/lvl039/rccg0o4pkp3v6nua 2. Grid 布局 // 定义接口 interface ImageCount {url:…

宿舍管理系统(servlet+jsp)

宿舍管理系统(servletjsp) 宿舍管理系统是一个用于管理学生宿舍信息的平台&#xff0c;支持超级管理员、教师端和学生端三种用户角色登录。系统功能包括宿舍管理员管理、学生管理、宿舍楼管理、缺勤记录、添加宿舍房间、心理咨询留言板、修改密码和退出系统等模块。宿舍管理员…

驱动-兼容不同设备-container_of

驱动兼容不同类型设备 在 Linux 驱动开发中&#xff0c;container_of 宏常被用来实现一个驱动兼容多种不同设备的架构。这种设计模式在 Linux 内核中非常常见&#xff0c;特别 是在设备驱动模型中。linux内核的主要开发语言是C&#xff0c;但是现在内核的框架使用了非常多的面向…

MySQLQ_数据库约束

目录 什么是数据库约束约束类型NOT NULL 非空约束UNIQUE 唯一约束PRIMARY KEY主键约束FOREIGN KEY外键约束CHECK约束DEFAULT 默认值(缺省)约束 什么是数据库约束 数据库约束就是对数据库添加一些规则&#xff0c;使数据更准确&#xff0c;关联性更强 比如加了唯一值约束&#…

责任链设计模式(单例+多例)

目录 1. 单例责任链 2. 多例责任链 核心区别对比 实际应用场景 单例实现 多例实现 初始化 初始化责任链 执行测试方法 欢迎关注我的博客&#xff01;26届java选手&#xff0c;一起加油&#x1f498;&#x1f4a6;&#x1f468;‍&#x1f393;&#x1f604;&#x1f602; 最近在…

林纳斯·托瓦兹:Linux系统之父 Git创始人

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 林纳斯托瓦兹&#xff1a;Linux之父、Git创始人 一、传奇人物的诞生 1. 早年生活与家…

8. RabbitMQ 消息队列 + 结合配合 Spring Boot 框架实现 “发布确认” 的功能

8. RabbitMQ 消息队列 结合配合 Spring Boot 框架实现 “发布确认” 的功能 文章目录 8. RabbitMQ 消息队列 结合配合 Spring Boot 框架实现 “发布确认” 的功能1. RabbitMQ 消息队列 结合配合 Spring Boot 框架实现 “发布确认” 的功能1.1 回退消息 2.备用交换机3. API说…

维港首秀!沃飞长空AE200亮相香港特别行政区

4月13日-16日&#xff0c;第三届香港国际创科展在香港会议展览中心盛大举办。 作为国内领先、国际一流的eVTOL主机厂&#xff0c;沃飞长空携旗下AE200批产构型登陆国际舞台&#xff0c;以前瞻性的创新技术与商业化应用潜力&#xff0c;吸引了来自全球17个国家及地区的行业领袖…

redis6.2.6-prometheus监控

一、软件及系统信息 redis&#xff1a;redis-6.2.6 redis_exporter&#xff1a;redis_exporter-v1.50.0.linux-amd64.tar.gz # cat /etc/anolis-release Anolis OS release 8.9 granfa; 7.5.3 二、下载地址 https://github.com/oliver006/redis_exporter/releases?page…