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

shell脚本的循环

文章目录

  • shell脚本的循环
    • while do done、until do done(不定循环)
      • 例题1
      • 例题2
      • 例题3
      • 例题4
    • for...do...done(固定循环)
      • 例题1
      • 例题2
      • 例题3
      • 例题4
    • for...do...done的数值处理
      • 例题
    • 搭配随机数与数组的实验
      • 例题1
      • 例题2
    • shell脚本的跟踪与调试
      • 使用案例

shell脚本的循环

除了if…then…fi 这种条件判断式之外,循环可能是程序当中最重要的一环了。循环可以不断地执行某个程序段落,直到用户设置的条件完成为止。所以,重点是那个【条件的完成】是什么,除了这种依据判断式完成与否的不定循环之外,还有另外一种已经固定要跑多少次循环状态,可称为固定循环状态。

while do done、until do done(不定循环)

一般来说,不定循环最常见的就是下面的两种状态了:

while  [ condition ]  # 中括号内的状态就是判断式 
do       # do是循环的开始
         程序段     
done     # done 是循环的结束

while的中文是【当…时】,所以,这种方式说的是【当condition条件成立时,就进行循环,直到condition的条件不成立才停止】的意思,还有另外一种不定循环的方式

until [ condition ]
do
       程序段
done

这种方式恰恰与while相反,它说的是【当condition条件成立时,就终止循环,否则就持续进行循环的程序段】

例题1

假设我要让用户输入yes或是YES才结束程序的执行,否则就一直告诉用户输入字符串

#!/bin/bash
# 程序说明:
#   输入yes/YES停止输出字符串
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/shelldir
export PATH
while [ "${yn}" != "yes" -a "${yn}" != "YES"  ]
do
      read -p "请输入yes/YES来停止该程序:" yn
done
      echo -e "\n您已经停止了该程序\a"

上面这个例题当中【当 ${yn} 这个变量不是 “yes” 且 ${yn} 也不是 "YES"时,就进行循环的程序】,如果输入了yes 或YES 就退出循环。

例题2

我们改变一下上述案例使用 until do done 的形式循环程序

#!/bin/bash
# 程序说明:
#   输入yes/YES停止输出字符串
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/shelldir
export PATH
until [ "${yn}" == "yes" -o "${yn}" == "YES"  ]
do
      read -p "请输入yes/YES来停止该程序:" yn
done
      echo -e "\n您已经停止了该程序\a"

上面这个例题当中【当 ${yn} 这个变量是"YES" 或是 “yes” 就退出循环】否则就持续进行循环。

例题3

如果我要计算1+2+…+100的结果呢?利用循环

#!/bin/bash
# 程序说明:
#    求1+...+100的和是多少
# 时间:
# 2023/05/04
PAHT=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/shelldir
export PATH
s=0
i=0
while [ "${i}" != "100" ]
do
   i=$(($i+1))
   s=$(($s+$i))
done
   echo "1+2+3...+100=${s}"

当你的执行结果为5050这个数据时就对了。

例题4

如果让用户自行输入一个数字,让程序1+2+3…加到你输入的数字为止,该如何编写呢?

#!/bin/bash
# 程序说明:
#    求1+...+到用户输入的那个数为止,求和。
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/shelldir
export PATH
read -p "请输入一个数字我将从1+到你输入的这个数字为止:" stdin
s=0
i=0
while [ "${i}" != "${stdin}" ]
do
   i=$((${i}+1))
   s=$((${i}+${s}))
done
  echo "1+2+3...加到你输入的这个数字,和为:${s} " 

是不是很简单,也可以使用until do done 来测试一下

for…do…done(固定循环)

相对于while、until的循环方式是必须要【符合某个条件】的状态,for这种语法,则是【已经知道要进行几次循环】的状态

它的语法为

for  var in con1 con2 con3 .....
do
     程序段
done

以上面的例子来说,这个${var}的变量内容在循环工作时:

  1. 第一次循环时,${var} 的内容为 con1
  2. 第二次循环时,${var} 的内容为 con2
  3. 第三次循环时,${var} 的内容为 con3

例题1

假设我有3种动物,分别是dog、cat、sheep(🐏),我想每一行都输出这样:【There are dogs…】之类的字样

#!/bin/bash
# 程序说明:
# 该程序判断动物园有哪些动物
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:~/shelldir
export PATH
echo -e "今天的动物园有哪些动物呢?"
for animal in dog cat tiger
do
      echo "有${animal}s"
done

例题2

如果我想要找到/etc/passwd 内的第一个字段,能不能通过管道命令的cut识别出单纯的账号名称后,以id分别检查用户的标识符与特殊参数(id 用户名)?

#!/bin/bash
# 程序说明:
# 该程序识别passwd的账户名称后,用id 账户名称查看用户标识符与特殊参数
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:~/shelldir
export PATH
cutpasswd=$(cut -d ':' -f1 /etc/passwd )   # 选取账号名称
for username in ${cutpasswd}               # 开始循环
do
   id ${username}
done

执行结果如下

[root@localhost shelldir]# sh userid.sh 
uid=0(root) gid=0(root)=0(root)
uid=1(bin) gid=1(bin)=1(bin)
uid=2(daemon) gid=2(daemon)=2(daemon)
uid=3(adm) gid=4(adm)=4(adm)
uid=4(lp) gid=7(lp)=7(lp)
uid=5(sync) gid=0(root)=0(root)
uid=6(shutdown) gid=0(root)=0(root)
uid=7(halt) gid=0(root)=0(root)
uid=8(mail) gid=12(mail)=12(mail)
uid=11(operator) gid=0(root)=0(root)
uid=12(games) gid=100(users)=100(users)
.....
...

例题3

假如我利用ping这个可以判断网络状态的命令,来进行网络状态的实际检测时,我想要检测的域名是本机所在的192.168.124.1~192.168.124.100网段,1~100 ,总不会我在for后面输入 1到100吗?

#!/bin/bash
# 程序说明:
# 该程序是检测网段的
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:~/shelldir
export PATH
network="192.168.124"                    # 定义一个域名
for segment in $(seq 1 100)              # 循环 1~100的数字
do
  ip="${network}.${segment}"             # 通过拼接得到一个完整的IP
  ping -c 1 -w 1 ${ip} > /dev/null 2>&1  # ping命令检测当前IP地址的网络状态
  if [ "$?" -eq "0" ]; then              # 如果返回0,则表示主机正常响应
     echo "${ip}是UP的"
  else
     echo "${ip}是DOWN的"             
  fi                                     # 别忘了加fi
done                                     # 和done

上面这一串命令执行后就可以显示出192.168.124.1~192.168.124.100共100台主机目前是否能够与这个太机器互通。如果你的network和我的不一样修改一下就行了,案例中的$(seq 1 100)是连续输出 1~100的数字,也可以写为【{1…100}】

例题4

我想要让用户输入某个目录文件名,然后我找出某目录内的文件名权限,应该怎么做呢?

#!/bin/bash
# 程序说明:
# 该程序是查看目录下的文件权限的
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:~/shelldir
export PATH
read -p "请输入目录文件名:" dir
if [ "${dir}" == "" -o ! -d "${dir}" ]; then
    echo "该${dir}目录不存在,请重新输入"
    exit 1
fi
filelist=$(ls ${dir})      # 列出所有该目录下的文件名称
for filename in ${filelist}
do
   perm=""
   test -r "${dir}/${filename}" && perm="${perm}可读"
   test -w "${dir}/${filename}" && perm="${perm}可写"
   test -x "${dir}/${filename}" && perm="${perm}可执行"
   echo "这个文件 ${dir}/${filename} 权限是${perm}"
done

for…do…done的数值处理

除了上述方法之外,for循环还有另外一种写法,语法如下:

for  (( 初始值; 限制值; 赋值运算 ))
do  
       程序段
done

这种语法适合于数值方面的运算当中,for后面括号内的三串内容意义是:

  • 初始值:某个变量在循环当中的起始值,直接类似 i=1 设置好;
  • 限制值:当变量的值在这个限制值的范围内,就继续进行循环,例如 i<=100
  • 赋值运算:每做一次循环,变量也变化,例如:i=i+1

值得注意的是,在【赋值运算】的设置上,如果每次增加1,则可以使用类似【i++】的方式,就是i每次循环都会增加1的意思。

例题

从1累加到用户输入的数值

#!/bin/bash
# 程序说明:
# 该程序是让用户输入个数字然后累加到用户输入的那个数字,求和
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:~/shelldir
export PATH
read -p "请输入一个数字我会从1+..累加到你输入的那个数字:" usershuzi
s=0
for (( i=1; i<=${usershuzi}; i=i+1 ))
do
    s=$((${s}+${i}))
done
    echo "1+2+3....+${usershuzi}=${s}"

搭配随机数与数组的实验

说到随机数肯定会用到系统给我提供的这个变量${RANDOM}

${RANDOM} 是一个 Bash 内置的环境变量,用于生成一个随机整数。每次调用 ${RANDOM} 时,都会生成一个 0 到 32767之间的随机整数。
可以使用以下方式来获取 ${RANDOM} 的值:

echo ${RANDOM}

也可以将 ${RANDOM} 的值赋值给变量:

my_random=${RANDOM}
echo ${my_random}

由于 ${RANDOM} 只是一个环境变量,所以它的值只在当前 Shell 进程中有效。如果需要在脚本中生成多个随机数,可以在需要的地方调用 ${RANDOM}。

例题1

假如你在家,你不知道吃什么饭,选择困难就很烦,那你就可以写个脚本,脚本搭配随机数来告诉你,今天中午吃啥好?执行这个脚本后,直接跟你说要吃什么。

应该怎么做呢?首先你得要将全部的店家输入到一组数组当中,再通过随机数的处理,去获取可能的数值,再将搭配到的数值显示出来即可。

#!/bin/bash
# 程序说明:
#   打印今天中午吃什么饭
# 时间:
# 2023/05/04
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:~/shelldir
export PATH
eat[1]="红烧肉"           # 定义一个数组
eat[2]="糖醋排骨"
eat[3]="小炒牛肉"
eat[4]="小炒五花肉"
eat[5]="平菇炒香干"
eat[6]="香菇炒芹菜"
eat[7]="喝西北风"
eat[8]="奥里给"
eat[9]="泡面"
eatnum=9                # 定义变量9,表示午餐可选的菜品
check=$(( ${RANDOM} * ${eatnum} /32767 +1))   # 通过随机数计算出今天中午吃什么菜
echo "你中午吃${eat[${check}]}"

上面案例中最重要的就是随机数了,【${RANDOM} * ${eatnum} /32767 +1 】计算出 check 变量的值,${RANDOM} 表示 Bash 内置的环境变量,用于生成一个随机整数,每次调用 ${RANDOM} 时,都会生成一个 0 到 32767 之间的随机整数,这里将其乘以菜品数量,再除以 32767,最后加 1,得到一个 1 到 9 之间的随机整数。

当我们执行上述案例时,就知道自己要吃啥了非常的方便。

例题2

那么如果我想吃3个菜呢?而且不能重复一样的,那应该怎么做?

#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:~/shelldir
export PATH
eat[1]="红烧肉"
eat[2]="糖醋排骨"
eat[3]="小炒牛肉"
eat[4]="小炒五花肉"
eat[5]="平菇炒香干"
eat[6]="香菇炒芹菜"
eat[7]="喝西北风"
eat[8]="奥里给"
eat[9]="泡面"
eatnum=9
eated=0
while [ "${eated}" -lt "3" ]; do 
    check=$(( ${RANDOM} * ${eatnum} /32767+1 ))
    mycheck=0
    if [ "${eated}" -ge "1"  ]; then
        for i in $(seq 1 ${eated})
        do
               if [ ${eatedcon[$i]} == $check  ]; then
                      mycheck=1
               fi
        done
    fi
    if [ "${mycheck}" == "0"  ]; then
       echo "你可以吃${eat[${check}]}"
       eated=$((${eated} + 1 ))
       eatedcon[${eated}]=${check}
    fi
done

代码解释

这段脚本用于随机选择三种食物,输出供用户选择。脚本中的变量和数组含义如下:

  • PATH:环境变量,指定可执行文件的搜索路径。

  • eat:数组,包含九种食物。

  • eatnum:变量,表示数组元素个数。

  • eated:变量,表示已经选择的食物数量,初始值为0。

  • check:变量,用于存储随机选择的食物在数组中的索引。

  • mycheck:变量,用于判断已经选择的食物中是否已经包含了当前选中的食物。

  • eatedcon:数组,用于存储已经选择的食物在数组中的索引。

while循环中的逻辑如下:

  • 当已经选择的食物数量小于3时,进行循环。

  • 生成一个随机数check,表示在数组中的索引。

  • 判断当前选中的食物是否已经被选择过,如果是则跳过,否则输出当前选中的食物,并将eated加1,同时将选中的食物在数组中的索引存入eatedcon数组中。

执行结果

[root@k8s-master-node1 shelldir]# sh noon_what_eat.sh 
你可以吃奥里给
你可以吃平菇炒香干
你可以吃糖醋排骨

shell脚本的跟踪与调试

脚本文件在执行之前,最怕就是出现语法错误的问题。那么我们如何调试呢?有没有办法不需要通过直接执行脚本文件就可以判断是否有问题?我们直接用bash的相关参数

sh [-nvx] scripts.sh
选项与参数:
-n:不要执行脚本,仅查询语法的问题
-v:再执行脚本前,先将脚本文件的内容输出到屏幕上
-x:将使用到的脚本内容显示到屏幕上

使用案例

测试dir_perm.sh 有无语法问题

[root@k8s-master-node1 shelldir]# sh -n dir_rwx.sh
# 若没有语法问题,则不会显示任何信息

将noon_what_eat.sh 的执行过程全部列出来

[root@k8s-master-node1 shelldir]# sh -x noon_what_eat.sh 
+ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin:/root/shelldir
+ export PATH
+ eat[1]=红烧肉
+ eat[2]=糖醋排骨
+ eat[3]=小炒牛肉
+ eat[4]=小炒五花肉
+ eat[5]=平菇炒香干
+ eat[6]=香菇炒芹菜
+ eat[7]=喝西北风
+ eat[8]=奥里给
+ eat[9]=泡面
+ eatnum=9
+ eated=0
+ '[' 0 -lt 3 ']'
+ check=2
.....
.......

http://www.kler.cn/news/16869.html

相关文章:

  • 『python爬虫』异常错误:request状态码是200,但是使用full xpath路径解析返回得到是空列表(保姆级图文)
  • Vue.js核心概念简介:组件、数据绑定、指令和事件处理
  • 1985-2021年全国31省一二三产业就业人数/各省分产业就业人数数据(无缺失)
  • 【C++】-关于类和对象的默认成员函数(中)-构造函数和析构函数
  • 操作系统——操作系统用户界面
  • C++入门(下)
  • 给你们讲个笑话——低代码会取代程序员
  • 360SEO 360搜索引擎算法的基础知识
  • Shell脚本3
  • 代码优美,搬砖不累:探索高质量代码之路
  • [架构之路-188]-《软考-系统分析师》-3-操作系统 - 图解页面替换算法LRU、LFU
  • 操作系统——第三章
  • 【FATE联邦学习】FATE是否支持batch分批训练?
  • 现代CMake高级教程 - 第 1 章:添加源文件
  • PowerJob基本概念
  • PHP学习笔记第一天
  • PHP+vue大学生心理健康评价和分析系统8w3ff
  • 每天一点C++——杂记
  • QT文本编辑与排版包含字体相关设置、段落对齐与排序方式
  • 树的刷题,嗝
  • 如果用上以下几种.NET EF Core性能调优,那么查询的性能会飙升
  • bash的进程与欢迎讯息自定义
  • C++命名空间的定义以及使用
  • C++煞笔笔记
  • 功能齐全的 DIY ESP32 智能手表设计之原理图讲解一
  • python实战应用讲解-【numpy数组篇】实用小技巧(九)(附python示例代码)
  • 这一篇LiveData掉不掉价(使用+粘性事件解决)
  • 07 Kubernetes 网络与服务管理
  • 项目沟通管理和干系人管理
  • 如何学习数据结构和算法