shell 循环遍历的详细用法

简介

    在 shell 脚本中,循环结构用于重复执行一组代码块,包括 for 循环、while 循环,可以用于遍历数字、字符串、数组、文件等。这篇文章会详细介绍这两种遍历方式,以及各种实例场景。

        

文章目录结构如下

1. 循环遍历的特点

2. 循环的方式

2.1. for循环

① 遍历整数

② 遍历数组

③ 遍历字符串

④ 遍历命令

⑤ 无限循环

⑥ 单行写法

2.2. while循环

① 基础用法

② 实例用法

2.3. 跳出循环

① continue 跳出当前循环

② break 跳出整个循环

③ 跳出多嵌套循环

3. 实际应用场景

3.1. while 按行读取内容

3.2. while 交互读取用户输入的变量

3.3. while 输出倒计时

3.4. for 输出进度条


        

1. 循环遍历的特点

刚开始接触编程的同学能理解什么是循环,但对 "遍历" 这个词可能有些陌生。遍历就是逐个访问集合中的每个元素,或逐个执行某个操作。那么循环遍历通俗来说就是:将多个数据循环读取出来,再对这些被读取出来的数据做各种操作。

那么循环遍历方法可以用在什么地方呢?举个例子:

后端需要一部分数据导入数据库,这些数据需要人工构造。

先使用 echo 来构造一行符合需求的数据

echo "1,zhang_san,18,man"

如果数据库需要3行数据,我们还是可以使用 echo

echo "1,zhang_san,18,boy"
echo "2,li_si,20,boy"
echo "3,wang_wu,16,girl"

如果需要1w行、10w行呢,还能使用手动敲10w行代码吗,这显然很耗费人力,所以循环的作用就体现出来了。代码示例

# 循环10w次
for i in {1..100000};do
    echo "${i},zhang_san,18,boy"
done

3行代码就能实现10w 行字符,是不是很方便呢。当然了,实际需求是很复杂的,但仍然可以使用循环方式解决。下面就带大家由浅到深慢慢学习。

        

2. 循环的方式

在 shell 中常见的循环方式有 2 种,它们的作用分别是:

  • for 循环:按次数循环某些字符串、数组、文件等。
  • while 循环:按条件循环,当条件为 True 即循环,条件为 False 则不循环。

这两种方式分别作用到不同的地方,下面就一起来学习吧!

2.1. for循环

① 遍历整数

遍历整数是最常见的方法,其中有2种写法,分别来看看他们怎么用吧

【写法一】按固定整数循环

for i in {1..5};do
    echo "循环第${i}次"
done
  • for  in 是固定语法,不能修改。
  • {1..5} 花括号是固定的,但里面的值可以修改 {开始值..结束值}。
  • i 不是固定的,可以随意修改,它的作用是读取花括号中的值。
  • do 是固定语法,不能修改,它表示循环开始。
  • 中间代码 echo 是自定义的,可以写其他代码。
  • done 是固定语法,不能修改,它表示循环结束。

我们来看看执行结果:

总共循环了 5 次,这 5 次是从花括号 {1..5} 读取的。

        

那么我们希望循环 3~7 怎么写呢?直接修改花括号的值

for i in {3..7};do
    echo "当前变量i的值是:${i}"
done

花括号 {3..7}:3表示开始,7表示结束

        

代码块中的 echo 命令是为了让我们了解循环的过程,来看一个简单的实例,向文件夹 ./tmp 下面创建 10 个文件。

for i in {1..10};do
    touch ./tmp/file${i}.txt
done

创建了 file1 ~ 10 的文件,共10个。 

        

【写法二】按判断循环

for ((i=1; i<=5; i+=1));do
    echo "当前i的值是:${i}"
done
  • for (()) 是固定语法,不能修改。
    • 括号中的 i=1 表示 i 的开始值为 1。
    • 括号中的 i<=5 表示只循环 i 小于等于 5,若大于5则退出循环。
    • 括号中的 i+=1 表示每循环一次后 i 的值都 +1。
  • do 是固定语法,不能修改,它表示循环开始。
  • 中间代码 echo 是自定义的,可以写其他代码。
  • done 是固定语法,不能修改,它表示循环结束。

执行结果与《写法一》差不多

        

《写法二》与《写法一》相比,有2个优势。

优势一、中间的数值可以跳跃,代码如下(i+=2

for ((i=1; i<=10; i+=2));do
    echo "当前i的值是:${i}"
done

设置 i+=2 表示每次 i 的值 +2,这样就可以循环奇数。

指定 +2 并不是固定的,在实际中还可以 +3、+4、+n 等。

        

优势二、可以读取变量

# 定义一个变量为5
var=5

# 读取变量的值做循环
for ((i=1; i<=var; i+=2));do
    echo "当前i的值是:${i}"
done

使用变量不仅仅可以指定最大值,最小值和跳跃值也可以指定

min=1
max=10
jump=3

# 读取变量的值做循环
for ((i=min; i<=max; i+=jump));do
    echo "当前i的值是:${i}"
done

        

② 遍历数组

由于数组中包含不同的字符串或数字,上述《目录 ①遍历整数》的语法将无法使用,所以我们需要换一种写法

# 定义一个数组
arr=('AAA' 123 'BBB' 789)

# 遍历数组
for i in ${arr[@]};do
    echo "当前数组的值为:${i}"
done

语法还是和《目录 ① 遍历整数》差不多,需要注意的是:遍历全部数组需要将变量这样写

${变量[@]}

按元素遍历,数组的分隔符默认空格。 

        

如果不需要变量数组中前2个元素,这样写 ${变量[@]:2}

# 定义一个数组
arr=('AAA' 123 'BBB' 789)

# 遍历数组
for i in ${arr[@]:2};do
    echo "当前数组的值为:${i}"
done

  • 只遍历前面3个元素:${变量[@]:0:3}
  • 只遍历后面3个元素:${变量[@]:(-3)}
  • 遍历中间 3~5 个元素:${变量[@]:2:3}

详细的数组用法见另一篇文章:https://blog.csdn.net/m0_61066945/article/details/135070671

        

除了指定数组的值,我们还可以通过命令向数组赋值,并使用 for 循环遍历

# 定义一个数组
arr=(`ls /tmp/`)

# 遍历数组
for i in ${arr[@]};do
    echo "当前数组的值为:${i}"
done

        

③ 遍历字符串

遍历字符串的方法和遍历数组的方式差不多,只是变量不同

# 定义一个字符串变量
var="AAA BBB CCC"

# 循环遍历这个变量
for i in ${var};do
    echo "当前变量的值为:${i}"
done

我们定义了一个变量 var,使用 for 循环将变量中的值读取出来。

注意:for 循环遍历变量时,in 后面的变量不能加引号,如果加引号就表示这是1个字符

for i in "${var}";do
    echo "当前变量的值为:${i}"
done

加上引号后,for 会认为这是一个字符,所以值循环一次。

我们不加引号可以将它理解成这样(直接遍历字符串)

for i in AAA BBB CCC;do
    echo "当前变量的值为:${i}"
done

        

还有一点需要注意,变量中默认分隔符是空格,这里列举了几种修改分隔符的写法:

IFS=$","      # 将分隔符指定为逗号
IFS=$"abc"    # 将分隔符指定为abc
IFS=$",: \n"  # 将分隔符指定为逗号、冒号、空格、换行

举个例子(将分隔符指定为逗号)

# 定义一个变量
var="AAA BBB,CCC"

OLD_IFS=${IFS}  # 读取当前分隔符
IFS=$","        # 指定分隔符为逗号

# 循环遍历这个变量
for i in ${var};do
    echo "当前变量的值为:${i}"
done

IFS=${OLD_IFS}  # 将分隔符修改会原来的值

结果如下

分隔符指定为逗号后,空格就不再生效。如果需要同时使用空格和逗号为分隔符,即设置为:IFS=$" ," 引号中同时包含一个空格和逗号。

        

④ 遍历命令

上面3种方法主要遍历固定的字符,在实际的场景中遍历命令的方式也是非常普遍的。

【案例一】遍历某个目录下以 .txt 结尾的文件

# find查找文件,for循环遍历
for file in $(find ./tmp -type f -name '*.txt');do
    echo "当前变量的值为:${file}"
done
  • 语法与前面差不多,命令放在 $( ) 中即可。

        

【案例二】遍历某个命令输出的结果

# seq输出一些数字
for i in $(seq 2 5);do
    echo "当前变量的值为:${i}"
done

        

⑤ 无限循环

无限循环的语法与上面不同,不需要读取啥,这样写

for ((;;));do
    echo "这是一个无限循环"
done

注意:这个方法会消耗一个cpu的资源,慎用!无限循环中最好加上 sleep

for ((;;));do
    echo "这是一个无限循环"
    sleep 1
done

        

⑥ 单行写法

单行写法语法如下

for i in {1..5};do 代码块1; 代码块2; done

单行写法与上面标准写法差不多,就是将换行符改为分号。如果将单行理解为4个部分的话,那么就是:(注意使用分号分隔)

【for 语法】;【do 开始循环】;【代码块】;【done 结束循环】

        

【案例1】创建10个文件

for i in {1..10};do touch tmp/file${i}.txt ;done

        

【案例二】给数组赋值 1~100 的奇数

# 定义一个空数组
arr=()

# 给数组赋值
for ((i=1; i<=100; i+=2));do arr+=(${i}) ;done

# 输出这个数组的值
echo ${arr[@]}

        

2.2. while循环

① 基础用法

while 不同于 for,for 是去读取某个值,while 是判断。如果判断结果为 True 则循环,如果判断结果为 False 则退出循环。

【案例一】直接给 while 加 true 表示无限循环

while true;do
    echo "我是一个while循环"
    sleep 1
done

        

【案例二】直接给 while 加 false 无法循环

while false;do
    echo "我是一个while循环"
    sleep 1
done

        

【案例三】在 false 前面加 !表示非 false,同 true

while ! false;do
    echo "我是一个while循环"
    sleep 1
done

        

通过上面3个案例总结出一个结论:只要判断的结果是正常的就可以循环,判断的结果是异常的则不循环。我们来判断一下数学运算。

# 定义一个变量
w=0

# 循环判断这个变量,只循环小于等于10的值
while [ ${w} -le 10 ];do
    echo "我是一个while循环, 当前w的值是:${w}"
    # 每循环一次,w的值+1
    (( w += 1 ))
done

        

除了判断某个变量,我们还可以判断命令是否正确

# 循环判断PID为4549的进程是否存在
while ps u -p 4549;do
    sleep 1
done

当进程存在时,一直循环;进程不存在时,退出循环。

        

② 实例用法

【案例一】判断端口是否被占用

while netstat -anpt |grep 3306; do
    echo "端口3306已被占用"
    sleep 1
done

端口号未被占用后,则退出循环。

        

【案例二】判断文件是否存在

file='./tmp/file.txt'

while [ ! -f ${file} ]; do
    echo "没有 ${file} 文件, 那么创建这个文件"
    touch ${file}
done

文件存在后,则退出循环 

        

【案例三】判断网络 192.118.168.254 是否通畅

while ! timeout 3 ping 192.118.168.254; do
    echo "192.118.168.254 无法ping通"
done

如果 IP 没有 ping 通,那么会一直去 ping,直到能够 ping 通。 

        

2.3. 跳出循环

在实际应用中,经常会出现循环到某个地方时,希望循环停止而不退出脚本,那么需要用到以下两个命令:

① continue 跳出当前循环

举个例子,当变量 i  = 3 时跳出当前循环,i 等于其他值时正常运行

# 循环1~5
for i in {1..5};do
    # 判断:如果i=3,跳出当前循环
    if [ ${i} -eq 3 ];then
        continue
    fi
    # 执行其他命令
    echo "当前变量i的值是:${i}"
done

只跳出当前循环,后面的循环继续 

        

② break 跳出整个循环

当变量 i = 3 时直接跳出整个循环

# 循环1~5
for i in {1..5};do
    # 判断:如果i=3,跳出当前循环
    if [ ${i} -eq 3 ];then
        break
    fi
    # 执行其他命令
    echo "当前变量i的值是:${i}"
done

跳出整个循环后,后面的 4、5 都不会循环

        

③ 跳出多嵌套循环

当遇到多层嵌套时,希望跳过某个循环时应该怎么指定呢?

我们先写一个3层嵌套的例子

for i in {1..2};do
    for j in {11..12};do
        for k in {21..22};do
            echo "当前各个变量结果:i=${i}, j=${j}, k=${k}"
        done
    done
done

每层输出2次,3层嵌套为 2³=8 次

        

将每层嵌套都打印字符,方便后面理解

for i in {1..2};do
    echo "第一层嵌套: ${i}"
    for j in {11..12};do
        echo "第二层嵌套: ${j}"
        for k in {21..22};do
            echo "第三层嵌套: ${k}"
        done
    done
done

        

【案例一】跳出当前层级的嵌套:break 1

for i in {1..2};do
    echo "第一层嵌套: ${i}"
    for j in {11..12};do
        echo "第二层嵌套: ${j}"
        for k in {21..22};do
            # 跳出当前嵌套
            break 1
            echo "第三层嵌套: ${k}"
        done
    done
done

对当前 break 的位置来说,当前层级就是第 1 层,所以跳出第 1 层后,就只剩下外面 2 层循环了。

        

【案例二】跳出上一层级的嵌套:break 2

for i in {1..2};do
    echo "第一层嵌套: ${i}"
    for j in {11..12};do
        echo "第二层嵌套: ${j}"
        for k in {21..22};do
            # 跳出上面一层嵌套
            break 2
            echo "第三层嵌套: ${k}"
        done
    done
done

对当前 break 的位置来说,当前层级就是第 1 层,上一层是第 2 层。所以在上一层执行到 break 时就会跳出,而第 2 层 break 上面的代码是可以正常执行的。

        

 【案例三】跳出上上层级的嵌套:break 3

for i in {1..2};do
    echo "第一层嵌套: ${i}"
    for j in {11..12};do
        echo "第二层嵌套: ${j}"
        for k in {21..22};do
            # 跳出上上层嵌套
            break 3
            echo "第三层嵌套: ${k}"
        done
    done
done

对当前 break 的位置来说,当前层级就是第 1 层,上上层是第 3 层。所以在上上层执行到 break 时就会跳出,而第 3 层 break 上面的代码是可以正常执行的。 

        

总结

不论是 continue 还是 break,如果不指定跳出的嵌套层级,那么就是跳出当前的嵌套。如果指定层级,那么当前层算是第1层,往上一层算低2层 ,再往上一层算是第3层,以此类推。

        

3. 实际应用场景

3.1. while 按行读取内容

虽然 for 循环也可以做到按行读取内容,但是需要修改分隔符(挺麻烦的),使用 while 就简单多了。代码如下:

while read str; do    # 通过read读取文件内容,赋值为变量str(str可以自定义)
    echo "当前文件内容:${str}"
done < ./file.txt     # 这里需要指定文件路径

        

3.2. while 交互读取用户输入的变量

# 定义一个普通数组
declare -a arr

while [ ${#arr[@]} -lt 2 ]; do    # 判断数组的个数小于等于2
    read -p "请输入一个整数: " input  # 交互读取变量
    arr+=(${input})               # 将变量追加到数组
done

# 计算数组
result=$(( ${arr[0]} + ${arr[1]} ))
echo "${arr[0]} + ${arr[1]} = ${result}"

        

3.3. while 输出倒计时

# 设置倒计时初始值
count=10

# 循环实现数字每秒自动变化
while [ ${count} -ge 0 ];do
  printf "\r倒计时: %2d" $count
  sleep 1
  (( count-- ))
done

echo -e "\n========== 结束 =========="

结果为动态,只能截几张静态图

        

3.4. for 输出进度条

# 设置总进度
total=100

# 循环输出进度条和百分比
for ((i=1; i<=total; i++)); do
    # 计算百分比
    percent=$((i * 100 / total))

    # 输出进度条和百分比
    printf "\r当前进度:%-$((total+1))s%2d%%" "$(perl -E "say '=' x ${i}")" $percent

    # 休眠0.1秒
    sleep 0.1
done; echo

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VS Code插件开发初步

文章目录 上手入口函数contributes 上手 欲善其事必先利其器&#xff0c;无论做什么开发&#xff0c;第一步肯定是下载工具链。VS Code开发主要用到两个东西&#xff0c;一个是项目的手脚架工具Yeoman&#xff0c;可通过yo来安装&#xff1b;另一个是VS Code的扩展时生成器gen…

工具系列:TensorFlow决策森林_(5)使用文本和神经网络特征

文章目录 设置使用原始文本作为特征使用预训练的文本嵌入同时训练决策树和神经网络构建模型训练和评估模型 欢迎来到 TensorFlow决策森林&#xff08; TF-DF&#xff09;的 中级教程。 在本文中&#xff0c;您将学习有关 TF-DF的一些更高级的功能&#xff0c;包括如何处理自…

uniapp中如何使用image图片

当在UniApp中使用图片时&#xff0c;可以通过<image>标签将图片显示在页面上。这个标签可以指定src属性来引用图片&#xff0c;并且可以通过mode属性来设置图片的显示模式。除此之外&#xff0c;还可以利用click事件来实现图片的点击事件。在编写代码时&#xff0c;要注意…

shell 编程中内置的变量(冷门又好用)

简介 分别盘点一下 shell 中的内置变量&#xff0c;真的巨好用&#xff01;&#xff01;&#xff01;包括&#xff1a;环境变量类、shell 变量类、终端设置类和其他一些变量。 常用的内置变量目录如下 1. 环境变量类 $MACHTYPE&#xff1a;机器类型 $OSTYPE&#xff1a;操作…

超声系统前端理论与模拟仿真-续

作者&#xff1a;蒋志强 本人同意他人对我的文章引用&#xff0c;但请在引用时注明出处&#xff0c;谢谢&#xff0e;作者&#xff1a;蒋志强 前言 近期整理了一下彩超前端及波束合成相关的内容&#xff0c;很早以前已经有过一次&#xff0c;这次把其它的内容总结一下&#xf…

【自定义磨砂动态背景】前端及pyqt6实现

如何实现一个自定义的磨砂动态背景呢&#xff1f; 这种效果看起来特别的高端&#xff0c;很新颖美观。 具体的效果可以看这里的演示&#xff1a;https://www.bilibili.com/video/BV1zj411H7wd/ 其实原理就是底层有多个多彩多边形在移动&#xff0c;然后再盖上一层模糊滤镜。 前…

测试服务器带宽(ubuntu)

apt install python3 python3-pippip3 install speedtest-clispeestest-cli

通过自然语言处理增强推荐系统:协同方法

一、介绍 自然语言处理 (NLP) 是人工智能的一个分支&#xff0c;专注于使机器能够以有意义且有用的方式理解、解释和响应人类语言。它包含一系列技术&#xff0c;包括情感分析、语言翻译和聊天机器人。 另一方面&#xff0c;推荐系统&#xff08;RecSys&#xff09;是旨在向用户…

机器视觉系统选型-避免畸变

在定位及高精度测量的系统中&#xff0c;镜头畸变的影响尤其重要 • 使用远心镜头 • 进行系统标定

【Unity+AI】SentisAI大模型植入Unity

相关教程 把AI模型放入Unity-手写数字识别【UnitySentis入门-1】_哔哩哔哩_bilibili Unity官方文档创建引擎以运行模型 |森蒂斯 |1.2.0-exp.2 (unity3d.com) 教程转载自&#xff1a;AI Tools for Game Dev 游戏开发人工智能工具/UnitySentis/01-Unity Sentis 入门.md chut…

听GPT 讲Rust源代码--src/tools(27)

File: rust/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs 文件rust/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs的作用是实施Clippy lint规则&#xff0c;检测产生潜在性能问题的字符转换代码&#xff0c;并给出相关建议。 在Rus…

机器人制作开源方案 | 森林管理员

​作者&#xff1a;李佳骏、常睿康、张智斌、李世斌、高华耸 单位&#xff1a;山西能源学院 指导老师&#xff1a;赵浩成、郜敏 1. 研究背景 森林作为地球上可再生自然资源及陆地生态的主体&#xff0c;在人类生存和发展的历史中起着不可代替的作用&#xff0c;它不仅能提供…

多功能视频编码标准 H.266/VVC

视频技术的最新进展潜在地增加了对流传输和广播视频内容的需求。在今日 人们依靠视频来相识并建立联系&#xff0c;借助超高清(Ultra High Definition&#xff0c;UHD)、虚 拟现实(Virtual Reality&#xff0c;VR)和 360 全景视频等技术&#xff0c;人们可以在线捕捉并分享最 快…

119. 杨辉三角 II(Java)

给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0 输出: [1]示例 3: 输入: rowIndex 1 输出: [1,1]提示…

彻底卸载Keil4

彻底卸载Keil4 双击 然后回到该软件的文件夹位置&#xff0c;把该文件夹删除即可&#xff0c;然后清一下回收站。

2024年软考电子商务设计师如何备考?考什么?

一、电子商务设计师概述&#xff1f; 电子商务设计师属于软考中级资格考试&#xff0c;软考是由国家人力资源和社会保障部&#xff08;原人事部&#xff09;、工业和信息化部&#xff08;原信息产业部&#xff09;领导的国家级考试&#xff0c;其目的是&#xff0c;科学、公正…

Hive05_DML 操作

1 DML 数据操作 1.1 数据导入 1.1.1 向表中装载数据&#xff08;Load&#xff09; 1&#xff09;语法 hive> load data [local] inpath 数据的 path [overwrite] into table student [partition (partcol1val1,…)];&#xff08;1&#xff09;load data:表示加载数据 &…

20231225在WIN10下使用SSH连接Ubuntu20.04.6

20231225在WIN10下使用SSH连接Ubuntu20.04.6 2023/12/25 23:03 https://jingyan.baidu.com/article/5552ef479e1856108ffbc9e3.html Win10怎么开启SSH功能 Win10怎么开启SSH功能,下面就一起来看看吧! 工具/原料 华硕天选4 Windows10 方法/步骤 点击左下角的开始菜单,打开Wind…

排序算法中In-place和Out-place

参考链接 排序方式中 In-place 和 Out-place&#xff1a; in-place 占用常数内存&#xff0c;不占用额外内存 假如问题规模是n&#xff0c;在解决问题过程中&#xff0c;只开辟了常数量的空间&#xff0c;与n无关&#xff0c;这是原址操作&#xff0c;就是In-place。 例 &…

【论文阅读】MCANet: Medical Image Segmentation with Multi-Scale Cross-Axis Attention

文章目录 摘要创新点总结实现效果总结 摘要 链接&#xff1a;https://arxiv.org/abs/2312.08866 医学图像分割是医学图像处理和计算机视觉领域的关键挑战之一。由于病变区域或器官的大小和形状各异&#xff0c;有效地捕捉多尺度信息和建立像素间的长距离依赖性至关重要。本文提…