Shell编程之循环语句与函数

Shell编程之循环语句与函数

一、for循环语句

1、for语句的结构

使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。在这里“,取值列表”称为 for 语句的执行条件,其中包括多个属性相同的对象,需要预先指定(如通讯录、IP 黑名单)。

for 语句的执行流程:首先将列表中的第一个取值赋给变量,并执行 do…done 循环体中的命令序列;然后将列表中的第二个取值赋给变量,并执行循环体中的命令序列……依此类推,直到列表中的所有取值用完,最后将跳至 done 语句,表示结束循环。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里插入图片描述

for语句的应用示例

示例1

批量添加用户用户名存放在users.txt文件中,每行一个

初始密码均设为123456

验证脚本

先新建一个文件存放用户名users.txt

#!/bin/bash
name=`cat /root/shell/users.txt`

for name  in $name
do
   echo "新增用户: $name"
   useradd $name
   echo "123456" | passwd --stdin $name &>/dev/null
   chage -d 0 $name
done

示例2

根据IP地址检查主机状态

IP地址存放在ipadds.txt文件中,每行一个使

用ping命令检测各主机的连通性

先新建一个文件存放需要连接的ip地址

#!/bin/bash
ip=`cat /root/shell/ipadds.txt`

for ip in $ip
do
  echo "检查连通性: $ip"
  ping -c 5 -i 0.2 -W 2 $ip &>/dev/null
  #判断ping的结果
  if [ $? -eq 0 ] then
    echo "$ip 已连通"
  else
     echo "$ip 不能连通   请检查配置 "
  fi
done

拓展

#!/bin/bash
#统计某个目录中所有文件的个数和大小
read -p "请指定目录:" dir

if [ ! -d $dir ] ; then
   echo "指定的不是不是目录,程序结束"
   exit
fi
#遍历目录
COUNT=0
SIZE=0
TOTAL=0
for file in `ls $dir`
do
   if  [ -f "$dir"/"$file" ] ; then
        COUNT=$((COUNT+1))
        SIZE=`stat "$dir"/"$file" | sed -n "2p" | awk '{print $1}' | sed "s/[^0-9]//g"`
        TOTAL=$((TOTAL+SIZE))
   fi
done
echo "$dir 目录中的文件个数: $COUNT"
echo "$dir 目录中的文件大小: $TOTAL 字节"

二、使用 while 循环语句

重复测试某个条件,只要条件成立则反复执行

在这里插入图片描述

for 循环语句非常适用于列表对象无规律,且列表来源已固定(如某个列表文件)的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定条件执行重复操作等情况,则更适合使用另外一种循环——while 语句。

1、while 语句的结构

使用 while 循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。因此,循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环。

while 语句的执行流程:首先判断 while 后的条件测试操作结果,如果条件成立,则执行 do…done 循环体中的命令序列;返回 while 后再次判断条件测试结果,如果条件仍然成立,则继续执行循环体;再次返回到 while 后,判断条件测试结果……如此循环,直到 while后的条件测试结果不再成立为止,最后跳转到 done 语句,表示结束循环使用while循环语句时有两个特殊的条件测试操作,即 true(真)和 false(假)使用 true 作为条件时,表示条件永远成立,循环体内的命令序列将无限执行下去,除非强制终止脚本(或通过 exit 语句退出脚本);反之,若使用 false 作为条件,则循环体将不会被执行。这两个特殊条件也可以用在 if 语句的条件测试中。

while语句应用示例

示例1

批量添加用户

用户名称以stu开头,按数字顺序进行编号

一共添加20个用户,即stu1、stu2、……、stu20

初始密码均设为123456

#!/bin/bash
i=1
while [  $i -le 20 ]
do
  echo "添加用户:stu$i "
  useradd stu$i
  echo "123456" | passwd --stdin stu$i &>/dev/null
  chage -d 0 stu$i
  let i++
done

示例2

从2000年到2030年哪些是闰年,哪些是平年闰年

判断条件:能被4整除但不能被100整除、或直接400整除的年份

#!/bin/bash
i=2000
while [  $i -le 2030 ]
do
  result1=$((i%4))
  result2=$((i%100))
  result3=$((i%400))
  if [ $result1 -eq 0 -a $result2 -ne 0 -o $result3 -eq 0 ] ; then
     echo "$i 是闰年..."
  else
     echo "$i 是平年"
  fi
  let i++
done

三、until 循环语句

1、until 语句的结构

重复测试某个条件,只要条件不成立则反复执行

until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真实继续执行循环,而 until 则是在条件为假时执行循环。

until 语句的执行流程:首先判断 until 后的条件测试操作结果,如果条件不成立,则执行 do…done 循环体中的命令序列;返回 until 后再次判断条件测试结果,如果条件仍然不成立,则继续执行循环体;再次返回到 until 后,判断条件测试结果……如此循环,直到 until后的条件测试结果成立为止,最后跳转到 done 语句,表示结束循环

在这里插入图片描述

until语句应用示例

示例1

计算1~50的和值

通过循环累加的方式计算1~50的和值

#!/bin/bash
i=1
until [  $i -gt 10 ]
do
  echo "当前数字:$i"
  let i++
done
echo "程序结束"

示例2

为指定用户发送在线消息

若用户不在线(未登录系统),则每10分钟试一次,直至用户登录系统后再发送信息

用户名与消息通过位置参数传递给脚本

#!/bin/bash
#检查用户是否在线

name=$1
msg=$2

tty=`who | grep -w $name | awk '{print $2}'`

until [ ! -z $tty ]
do
 # echo "检查 $name 是否在线"
  sleep 5
  tty=` who | grep -w $name | awk '{print $2}'`
done
echo $msg | write $name $tty
#echo "消息已发送,程序结束"

四、Shell函数

  • 将命令序列按格式写在一起
  • 可方便重复使用命令序列

1.函数的定义方法

方法1:

function 函数名 {
    command
}

方法2:

函数名() {
    command
}
  • 函数定义完之后并不会自动执行,需要调用才行
  • 好处在于可以写一段功能代码作为函数,有需要就直接调用定义的时候哪怕出现语法错误也没关系,不调用就不会报错
  • 当然我们写函数最终目的还是为了调用,为了实现某个功能块。
函数的调用

直接在脚本里定义函数的代码块后写函数名即可完成调用。

函数名  [参数1] [参数2]
#!/bin/bash
function fun1 {
    echo "this is a function!"
}

fun1

2.函数的参数

参数的用法

函数名称 参数1 参数2 参数3 ......

参数的表示方法

$1 $2 $3 … ${10} ${11} …

Shell函数

定义和调用函数、传递参数

在这里插入图片描述

在这里插入图片描述

3.函数返回值

return表示退出函数并返回一个退出值,脚本中可以用$? 变量显示该值使用原则

  • 函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码
  • 退出状态码必须是0~255,超出时值将为256取余

在这里插入图片描述

在这里插入图片描述

案例:返回用户输入的数字的两倍
#!/bin/bash
function

 test1 {
    read -p "请输入一个数字:" num
    return $[$num*2]
}
test1
echo $?

在这里插入图片描述

函数传参
两个数求和
#!/bin/bash
sum(){
    read -p "请输入第一个数:" NUM1
    read -p "请输入第二个数:" NUM2
    echo "你输入的两个数为: $NUM1$NUM2 "
    SUM=$(( NUM1 + NUM2 ))
    echo "两个数的和为: $SUM"
}
sum

在这里插入图片描述

通过脚本传递参数给函数中的位置参数
#!/bin/bash
add (){
    let sum=$1+$2
    echo $sum
}

add $1 $2   # 调用脚本时传递参数
add 20 30

在这里插入图片描述

函数的递归
#!/bin/bash
fa () {
    if [ $1 -eq 1 ]
    then
        echo 1
    else
        local tp=$[$1 - 1]
        local res=$(fa $tp)
        echo $[$1 * $res]
    fi
}

read -p "请输入:" num
res=$(fa $num)
echo $res

在这里插入图片描述

五.数组的定义

数组的定义方法

方法1:

num=(11 22 33 44)

方法2:

num=([0]=55 [1]=66 [2]=77 [4]=88)

方法3:

list="11 12 13 14"
num=($list)

方法4:

数组名[0]="value"
数组名[1]="value"
数组名[2]="value"
获取数组的长度
arr_length=${#arr_number[*]}
获取数据列表
echo ${arr_number[*]}
echo ${arr_number[@]}
数组元素遍历
#!/bin/bash
arr=(1 2 3 4 5 6)
for i in ${arr[*]}
do
    echo $i
done

在这里插入图片描述

数组(元素)替换
arr=(1 2 3 4 5)
echo ${arr[@]/3/55}   # 替换元素3为55
echo ${arr[@]}
arr=(${arr[@]/3/55})  # 实现改变原有数组,如果注释掉原数组不变。
echo ${arr[@]}

在这里插入图片描述

数组删除
arr=(1 2 3 45)
unset arr            # 删除数组
echo ${arr[*]}

arr=(1 2 3 4 5)
unset arr[4]         # 删除第四个元素
echo ${arr[*]}

在这里插入图片描述

数组排序算法:冒泡排序

冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

算法思路
#!/bin/bash
array=(90 70 60 40 50 30)
echo "old_array:${array[*]}"
lt=${#array[*]}
# 定义比较轮数,比较轮数为数组长度减1,从1开始
for ((i=1; i<$lt; i++))
do
    # 确定比较元素的位置,比较相邻两个元素,较大的数往后放,比较次数随比较轮数而减少
    for ((j=0; j<$lt-i; j++))
    do
        # 定义第一个元素的值
        first=${array[$j]}
        # 定义第二个元素的值
        k=$[$j+1]
        second=${array[$k]}
        # 如果第一个元素比第二个元素大就互换
        if [ $first -gt $second ]
        then
            # 把第一个元素值保存到临时变量中
            temp=$first
            # 把第二个元素值赋给第一个元素
            array[$j]=$second
            # 把临时变量(也就是第一个元素原值)赋给第二个元素
            array[$k]=$temp
        fi
    done
done
# 输出排序后的数组
echo "new_array:${array[*]}"

在这里插入图片描述

输入数组元素并排序
#!/bin/bash
# 存入元素
k=0
while true
do
    read -p "是否继续存入元素:" doing
    if [ $doing == "no" ];then
        break
    fi
    read -p "请输入第$[$k+1]个元素:" key
    score[$k]=$key
    let k++
done
# 外层为轮
for ((i=1;i<${#score[*]};i++));do
    # 内层为次
    for ((j=0;j<${#score[*]}-i ;j++));do
        # 两数交换
        if [ ${score[$j]} -gt ${score[`expr $j + 1`]} ];then
            tmp=${score[`expr $j + 1`]}
            score[`expr $j + 1`]=${score[$j]}
            score[$j]=$tmp
        fi
    done
done
echo ${score[*]}

ray:${array[*]}"


[外链图片转存中...(img-DSf2up1f-1723197200361)]

### 6.8 输入数组元素并排序

```bash
#!/bin/bash
# 存入元素
k=0
while true
do
    read -p "是否继续存入元素:" doing
    if [ $doing == "no" ];then
        break
    fi
    read -p "请输入第$[$k+1]个元素:" key
    score[$k]=$key
    let k++
done
# 外层为轮
for ((i=1;i<${#score[*]};i++));do
    # 内层为次
    for ((j=0;j<${#score[*]}-i ;j++));do
        # 两数交换
        if [ ${score[$j]} -gt ${score[`expr $j + 1`]} ];then
            tmp=${score[`expr $j + 1`]}
            score[`expr $j + 1`]=${score[$j]}
            score[$j]=$tmp
        fi
    done
done
echo ${score[*]}

#!/bin/bash
# 存入元素
k=0
while true
do
    read -p "是否继续存入元素:" doing
    if [ $doing == "no" ];then
        break
    fi
    read -p "请输入第$[$k+1]个元素:" key
    score[$k]=$key
    let k++
done
# 外层为轮
for ((i=1;i<${#score[*]};i++));do
    # 内层为次
    for ((j=0;j<${#score[*]}-i ;j++));do
        # 两数交换
        if [ ${score[$j]} -gt ${score[`expr $j + 1`]} ];then
            tmp=${score[`expr $j + 1`]}
            score[`expr $j + 1`]=${score[$j]}
            score[$j]=$tmp
        fi
    done
done
echo ${score[*]}

~~~

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/db8522ca00d14ee4981d9ae9b8df36be.png)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值