小阿轩yx-Shell 编程之循环语句与函数

小阿轩yx-Shell 编程之循环语句与函数

for 循环语句

可以很好地解决顺序编写异常烦琐、困难重重的全部代码

(){}:里边写的都是命令

):不能嵌套

$():可以嵌套,适合更复杂的命令

命令执行的两种方式

  • 交互式:在命令行里直接写入命令,有多少需求就写入多少次命令
  • 非交互式:把命令写入到脚本里去执行,人就不用在脚本里敲命令

(注:交互:人与机器之间的一种交流)

# 不想看到消息提示就放到(&>/dev/null黑洞)里面
echo "123456" | passwd --stdin $uname &>/dev/null

 echo:作用回显(将内容显示到屏幕)

for 语句的结构

(注:for循环语句需要有一个取值列表)

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

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

# 创建用户的列表文件
[root@localhost ~]# vim /root/users.txt
zhangsan
lisi
wangwu
# 编辑批量添加用户的脚本
[root@localhost ~]# vim uaddfor.sh
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
   useradd $UNAME
   echo "123456" | passwd --stdin $UNAME &>/dev/null
done
给脚本赋予执行权限
[root@localhost ~]# chmod +x uaddfor.sh
# 测试并确认执行结果
[root@localhost ~]# ./uaddfor.sh
[root@localhost ~]# cat /etc/passwd

 编辑批量删除用户的脚本

[root@localhost ~]# vim udelfor.sh
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
    # 不想看到消息提示就放到黑洞里
   userdel -r $UNAME &>/dev/null
   
done
# 给脚本赋予执行权限
[root@localhost ~]# chmod a+x udelfor.sh
# 测试并确认执行结果
[root@localhost ~]# ./udelfor.sh
[root@localhost ~]# cat /etc/pwd

根据 IP 地址列表检查主机状态

# 创建IP地址列表文件
[root@localhost ~]# vim /root/ipadds.txt
172.16.1.1
172.16.1.111
172.16.1.222
192.168.10.10
# 编辑循环检查各主机的脚本
[root@localhost ~]# vim chkhosts.sh
#!/bin/bash
HLIST=$(cat /root/ipadds.txt)
for IP in $HLIST
do
   ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
   if [ $? -eq 0  ]
   then
      echo "Host $IP is up."
   else
      echo "Host $IP is down."
   fi
done
# 添加执行权限
[root@localhost ~]# chmod a+x chkhost.sh
# 测试并确认执行结果
[root@localhost ~]# bash chkhosts.sh
  • 需要指定一个变量及可能的取值列表

        取值列表:称为 for 语句的执行条件,其中包括多个属性相同的对象,需要预先指定

  • 针对每个不同的取值重复执行相同的命令序列
  • 直到变量值用完退出循环从而不会进入死循环

使用 while 循环语句

可用于

  • 求控制循环次数
  • 操作对象按数字顺序编号
  • 按特定条件执行重复操作

while 语句的结构

while 条件测试操作 
do 
命令序列 
done
# 批量添加用户脚本
[root@localhost ~]# vim uaddwhile.sh
#!/bin/bash
PREFIX="stu"
i=1
while [ $i -le 20 ]
do
    useradd ${PREFIX}$i
    echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null
    let i++
done
# 添加执行权限
[root@localhost ~]# chmod a+x uaddwhile.sh
# 测试并确认执行结果
[root@localhost ~]# bash uaddwhile.sh 
[root@localhost ~]# grep "stu" /etc/passwd | tail -3

或者

#!/bin/bash
PREFIX="stu"
i=1
while [ $i -le 20 ]
do
    useradd ${PREFIX}$i
    echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null
    i=`expr $i + 1`
done
# 批量删除用户脚本
[root@localhost ~]# vim udelwhile.sh
#!/bin/bash
PREFIX="stu"
i=1
while [ $i -le 20 ]
do
     userdel -r ${PREFIX}$i
     let i++

done
# 添加执行权限
[root@localhost ~]# chmod a+x udelwhile.sh
# 测试并确认执行结果
[root@localhost ~]# bash udelwhile.sh
id stu20

猜价格 

[root@localhost ~]# vim pricegame.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格范围为0-999,猜猜看是多少?"
while true
do
    read -p "请输入你猜测的价格数目:" INT
    let TIMES++
    if [ $INT -eq $PRICE ] ; then
        echo "恭喜你答对了,实际价格是 $PRICE"
        echo "你总共猜测了$TIMES 次"
        exit 0
    elif [ $INT -gt $PRICE  ] ; then
        echo "太高了!"
    else
        echo "太低了!"
    fi
done

( 注:linux中随机数的取值范围是0--32767,和什么数取余,取余后的最大数就是谁,不包含该数字)

# 添加执行权限
[root@localhost ~]# chmod a+x pricegame.sh
# 测试并确认执行结果
[root@localhost ~]# bash pricegame.sh
  • 不需要取值列表
  • 可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。
  • 在脚本应用中,要避免出现死循环的情况,否则后边的命令操作将无法执行。
  • 因此,循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环
while 循环语句的两个结果(只有两个)
  • true(真)
  • false(假)

用 true 作为条件时

  • 表示条件永远成立,循环体内的命令序列将无限执行下去,除非强制终止脚本(或通过 exit 语句退出脚本)

反之用 false 作为条件

  • 则循环体将不会被执行

(注:这两个特殊条件也可以用在 if 语句的条件测试中)

until 循环语句

直到性循环

(注:一般处理一些有特色的)

until 循环语句的结构

until 条件测试操作 
do 
done

案例一

[root@localhost ~]# vim until_v1.sh 
#!/bin/bash 
i=0;s=0 
until [ $i -eq 50 ] 
do 
let "i=$i+1";let "s=$s+$i" 
done 
echo 'sum(1..50)='$s

# 添加执行权限
[root@localhost ~]# chmod +x sum1to50_until_v1.sh

# 测试结果
[root@localhost ~]# bash sum1to50_until_v1.sh 

 案例二

[root@localhost ~]# vim until_v2.sh 
var1=100
until [ $var1 -eq 0 ]
do
        echo $var1
        var1=$[ $var1 - 25 ]
done

# 添加执行权限
[root@localhost ~]# chmod +x until_v2.sh

# 测试结果
[root@localhost ~]# bash until_v2.sh
  • 与 while 循环类似
  • while 循环能实现的脚本 until 同样也可以实现
区别
  • while 循环在条件为真时继续执行循环
  • 而 until 则是在条件为假时执行循环

Shell 函数

代码的重用

local:作用将变量设置为局部变量

函数的用法

案例一

[function] 函数名() { 
[return x] 
} 
[root@localhost ~]# cat exa1.sh 
#!/bin/bash
zhangsan() {
	echo "my name is zhangsan"
}
 
lisi() {
	echo "my name is lisi"
}
 
zhangsan
lisi
# 测试结果
[root@localhost ~]# bash exa1.sh

案例二 

[root@localhost ~]# cat exa2.sh 
#!/bin/bash
name() {
	echo "my name is $1"
}
name $1
# 测试结果
[root@localhost ~]# bash exa2.sh zhangsan
my name is zhangsan
[root@localhost ~]# bash exa2.sh lisi
my name is lisi

案例四 

[root@localhost ~]# vim fun_scope.sh 
myfun () 
{ 
    local i 
    i=8 
    echo $i 
}
i=9 
myfun 
echo $i
# 添加执行权限
[root@localhost ~]# chmod +x fun_scope.sh 
# 测试结果
[root@localhost ~]# bash fun_scope.sh

(注:通过内置命令 local 将变量的值限定在函数内部)

Shell 脚本执行的过程中

  • 函数被置于内存中
  • 每次调用函数时不需要从硬盘读取,因此运行的速度比较快

Shell 编程中函数并非是必须的元素

使用函数的好处

  • 可以对程序进行更好的组织
  • 将一些相对独立的代码变成函数
  • 可以提高程序可读性与重用性
  • 避免编写大量重复代码
  • “function”关键字表示定义一个函数,可以省略;
  • “{”符号表示函数执行命令的入口,该符号可以与函数名同行也可以在函数名下一行的句首;
  • “}”符号表示函数体结束,两个大括号之间{ }是函数体;
  • “命令序列”部分可以是任意的 Shell 命令,也可以调用其他函数;
  • “return”表示退出函数返回一个退出值,通过返回值判断执行是否成功,也可以使用 exit 终止整个 Shell 脚本

Shell 函数调用的方法为

函数名 [参数 1] [参数 2]

函数变量的作用范围

  • Shell 脚本中函数的执行不会开启一个新的子 Shell,而是仅在当前定义的 Shell环境中有效
  • 如果 Shell 脚本中的变量没有经过特殊设定,默认在整个脚本中都是有效的
  • 编写脚本时,有时需要将变量的值限定在函数内部,可以通过内置命令 local 来实现
  • 函数内部变量的使用,可以避免函数内外同时出现同名变量对脚本结果的影响

函数的参数

  • 在使用函数参数时,函数名称在前参数在后,函数名和参数之间用空格分隔,可以有多个参数,参数使用$1、$2、$3……的方式表示
  • 以此类推,从第 10 个参数开始,调用方法为${10},不加大括号无法调用成功

递归函数

递归算法的经典例子是计算阶乘

案例

[root@localhost ~]# vim fun_recursion.sh
#!/bin/bash 
function factorial { 
	if [ $1 -eq 1 ] 
	then 
		echo 1 
	else 
		local temp=$[ $1 - 1 ] 
		local result=$(factorial $temp) 
		echo $[ $result * $1 ] 
	fi
} 
 
read -p "Enter value: " value 
result=$(factorial $value) 
echo "The factorial of $value is: $result"
# 测试结果
[root@localhost ~]# bash fun_recursion.sh

调用自己本身的函数实现递归函数

Linux 系统上编写 Shell脚本的时候,经常需要递归遍历系统的目录,列出目录下的文件和目录,逐层递归列出,并对这些层级关系进行展示

Shell 数组

Shell 脚本中,数组是一种常见的数据结构

主要的应用场景包括

数组常用定义方法包括以下几种

方法一

数组名=(value0 value1 value2 ...)

方法二

数组名=([0]=value [1]=value [2]=value ...)

方法三

列表名=”value0 value1 value2 ...” 
数组名=($列表名)

方法四

数组名[0]=”value” 
数组名[1]=”value” 
数组名[2]=”value”
......

获取数组的长度 

[root@localhost ~]# arr_number=(1 2 3 4 5) 
[root@localhost ~]# arr_length=${#arr_number[*]} 
[root@localhost ~]# echo $arr_length 
5
[root@localhost ~]# arr_length_1=${#arr_number[@]}
[root@localhost ~]# echo $arr_length_1
5

读取某下标赋值

[root@localhost ~]# arr_index2=${arr_number[2]} 
或
[root@localhost ~]# echo ${arr_number[2]} 
//第三个元素 
[root@localhost ~]# echo $arr_index2 
3

或
echo ${aaa[3]}

数组遍历 

[root@localhost ~]# vim array_traverse.sh 
#!/bin/bash 
arr_number=(1 2 3 4 5) 
for v in ${arr_number[@]} 
do
echo $v 
done
# 添加执行权限
[root@localhost ~]# chmod +x array_traverse.sh
# 测试结果
[root@localhost ~]# bash array_traverse.sh

数组切片 

[root@centos-7 ~]# arr=(1 2 3 4 5)
//输出整个数组 
[root@centos-7 ~]# echo ${arr[@]} 
1 2 3 4 5
//${数组名[@或*]:起始位置:长度} 
[root@centos-7 ~]# echo ${arr[@]:0:2}
1 2 
[root@centos-7 ~]# echo ${arr[@]:2:3} 
3 4 5 

数组替换 

[root@centos-7 ~]# arr=(1 2 3 4 5)
// ${数组名[@或*]/查找字符/替换字符} 
[root@centos-7 ~]# echo ${arr[@]/4/66}
1 2 3 66 5
// 并不会替换数组原有内容 
[root@centos-7 ~]# echo ${arr[@]} 
1 2 3 4 5
// 要实现改变原有数组,可通过重新赋值实现 
[root@centos-7 ~]# arr=(${arr[@]/4/66}) 
[root@centos-7 ~]# echo ${arr[@]} 
1 2 3 66 5

数组删除 

[root@centos-7 ~]# arr=(1 2 3 4 5) 
[root@centos-7 ~]# unset arr
// 删除数组 
[root@centos-7 ~]# echo ${arr[*]} 
[root@centos-7 ~]# arr=(1 2 3 4 5) 
[root@centos-7 ~]# unset arr[2] 
// 删除第三个元素 
[root@centos-7 ~]# echo ${arr[*]} 
1 2 4 5

(注:$* 和 $@ 都表示传递给函数或脚本的所有参数)

区别

  • $* 和 $@ 不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔

被双引号" "包含时,就会有区别

"∗ " 会 将 所 有 的 参 数 从 整 体 上 看 做 一 份 数 据 , 而 不 是 把 每 个 参 数 都 看 做 一 份 数 据 

"@"仍然将每个参数都看作一份数据,彼此之间是独立的

Shell 脚本调试

[root@localhost ~]# vim aaa.sh 

#!/bin/bash 
set -x 
##开启调试模式 

read -p "请输入您的分数(0-100):" GRADE 
if [ $GRADE -ge 85 ] && [ $GRADE -le 100 ] 
    then 
        echo "$GRADE 分!优秀" 
set +x 
##关闭调试模式 

elif [ $GRADE -ge 70 ] && [ $GRADE -le 84 ] 
    then
        echo "$GRADE 分,合格" 
else 
        echo "$GRADE 分?不合格" 
fi
  • 把复杂的脚本简单化
  • 要思路清晰
  • 分段实现

(注:执行脚本时出现错误后,不要只看提示的错误行,要观察整个相关的代码段)

为避免编写的脚本出错,除了在编写脚本时注意书写规范,排除语法错误,更重要的是利用调试脚本工具来调试脚本。

echo 命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入 echo 命令,采用的是分段排查的方式

(注:除了 echo 命令之外,bash Shell 也有相应参数可以调试脚本)

常用参数的具体含义为

  • -n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任何内容,如果有问题会提示报错
  • -v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示
  • -x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数

 小阿轩yx-Shell 编程之循环语句与函数

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

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

相关文章

全球伦敦银收盘时间一致吗

跟伦敦金市场相似,伦敦银市场也是一个全球化的无形市场,无论来自世界上什么地方的投资者参与其中,都可以得到全天接近24个小时的连贯行情,只要精力足够,根本不用担心没有交易获利的机会。但由于交易平台始终有维护的需…

Linux:线程

文章目录 前言1. 线程概念1.1 什么是线程1.2 线程比进程更加轻量化1.3 虚拟地址到物理地址的转化物理内存的管理页表 1.4 线程的优点1.5 线程的缺点1.6 线程异常1.7 线程用途 2. 进程 vs 线程3. 线程控制3.1 线程创建3.2 线程退出3.3 线程等待3.4 分离线程3.5 线程取消 4. 线程…

磁盘问题——外部、动态,无法读取

今天,小编又遇到事了,给同事换个电脑,要把他原来的硬盘拆过去,一开始电脑都准备好了,就差拆他的硬盘了,结果装过去,问题来啦!如下图所示: 这下可咋搞呢!我先用…

专业145+总410+成电电子科技大学858信号与系统考研经验电子信息与通信工程,抗干扰,空天,资环,真题,大纲,参考书。

今年考研总分410,专业课858信号与系统145,顺利上岸成电,毕设已经搞得七七八八,就等毕业了,抽空整理回顾一下去年的复习,给群里的同学提供一些参加,少走弯路,对于整体复习的把握有个大概得规划。…

抽象类和接口(2)

1、接口 1、接口的概念 接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。 在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。 2、语法规则 接口的定义格式与定义…

Python考试练习题---day1

1.计算2的n次幂结果的后3位 获得用户输入的一个数字N,计算并输出2的N次幂结果的后3位。 【输出样例】-----因为2的10次方等于1024 输入10输出024 ninput() print(str(2**eval(n))[-3:]) 2.分割四位正整数 例1: 编写程序,提示用户从键盘…

2、python环境的安装-mac系统下

打开官网,downloads下边有macOS,点击: 选择最新版本,点击,进入下边的页面,一直往下滑,看到files中有个macOS的版本,点击下载 点击下载后是pkg的安装包,点击安装。 一步步…

350种类型、10W+量级的API,企业应该怎么管?

忽如一夜春风来,万物皆可API。 在互联网时代,API无处不在:企业对外开放的数据、服务和业务能力,以API的形式提供给合作方;企业内部应用与应用、App与App之间的通信,通过API进行;甚至应用内部的…

机器视觉HALCON:3.图像获取,运算,率噪,滤波(边缘),锐化

目录 图像获取生成单通道图像图像运算加法运算减法运算乘法运算除法 仿射变换图像平滑(噪点处理)高斯滤波均值滤波中值滤波多图像均值 边缘滤波索贝尔滤波凯尼滤波 图像锐化索贝尔锐化拉普拉斯锐化高通滤波锐化几种锐化方式对比 图像获取 用到的函数&…

液氮罐内部会污染吗

液氮罐是一种常见的存储液态氮的设备,广泛应用于科研、生物医药、食品冷冻等领域。但是,人们对于液氮罐内部是否会产生污染一直存在疑问。 我们来看液氮罐内部可能的污染源。液氮罐内部主要存在以下几种潜在的污染来源:气体污染、杂质污染、…

MySQL数据处理增删改

数据处理增删改DML 由于约束,以下操作都有可能执行失败(后面讲约束) 插入数据 INSERT 基础添加:VALUES 值的顺序必须和表中字段顺序相同 INSERT INTO class VALUES(1,王小,10); 向指定字段添加: 值的顺序和指定…

使用canarytokens进行入侵检测

canarytokens 基本概念 canarytokens是一种用于识别网络入侵的工具。它们是一种虚拟的“蜜罐”,可以在网络上放置,当有人尝试访问它们时,可以立即触发警报,以便及时发现潜在的安全威胁。这些token可以是各种形式,可以…

工业触摸屏一般用哪种

工业触摸屏一般使用以下几种类型:1.电阻式触摸屏:电阻式触摸屏是最常见和常用的工业触摸屏类型之一。它由两层导电层组成,当屏幕上的物体接触到触摸屏时,两个导电层之间会发生电阻变化,触摸点的坐标信息可以通过测量电…

不仅能逃生,更能自动灭火!神奇的全氟己酮灭火毯的原理是什么?

很多朋友对灭火毯的印象,还停留在火灾发生时披覆在身上逃生时使用,可以隔离火源。近年来兴起的全氟己酮自动灭火毯可以说大为颠覆大家的想法,这是一条真的可以自动灭火的神奇灭火毯!为什么能做到这一点?全氟己酮灭火毯…

黑马聚合的分类及实现

1、什么是聚合? 聚合是对文档数据的统计、分析、计算 聚合的常见种类有哪些? 桶(Bucket)聚合:用来对文档做分组 TermAggregation:按照文档字段值分组 Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组 度量(…

LVM与磁盘配额09

一、LVM 1、lvm概述 lvm (logical volume manager ):逻辑卷管理 linux系统下对硬盘分区的一种管理机制。 场景:lvm机制特别适合于管理大存储设备。 作用:可以动态的对硬盘进行扩容 。 逻辑上的磁盘,概…

IP协议说明

文章目录 前言一、IP协议的简介二、IP数据报1.IP 数据报结构2.IP 数据报的分片解析3.IP 数据报的分片重装 三、IP 数据报的输出四、IP 数据报的输入 前言 IP 指网际互连协议, Internet Protocol 的缩写,是 TCP/IP 体系中的网络层协议。设计 IP 的目的是…

QGis3.34.5工具软件保存样式,软件无反应问题

在使用QGis软件保存SLD样式的时候,每次保存样式,软件都进入无反应状态,导致无法生成样式文件 百度中多次查询问题点,终未能在在3.34.5这个版本上解决问题。 考虑到可能是软件本身问题,于是删除了3.34.5这个版本&#x…

Java面试八股之自旋是什么意思

Java中的自旋是什么意思 自旋是多线程编程中的一种同步机制,尤其在Java中与锁的实现密切相关。当一个线程尝试获取某个锁(如内置锁或显式锁)时,如果锁已被其他线程持有,通常的做法是将该线程置于阻塞状态,…

基于遗传优化的Sugeno型模糊控制器设计matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于遗传优化的Sugeno型模糊控制器设计matlab仿真,通过遗传优化算法优化模糊控制器的隶属函数参数,从而获得较优的控制效果。 2.系统仿真结果 3.核心程序与模型 …