shell脚本基础之函数与数组详解

目录

一、shell函数

1、shell函数的概念

2、shell函数的用法

2.1 定义函数

2.2 调用函数

2.3 函数作用范围

2.3.1 调用函数的范围

2.3.2 全局作用域和局部作用域

3、 函数返回值

3.1 系统默认的返回值

3.2 return语句

4、函数传参

5、查看函数列表

6、删除函数

7、 函数递归

7.1 函数递归死循环

7.1.1 模拟死循环

7.1.2 fork炸弹

7.2 阶乘

二、shell数组

1、shell 数组的概念

2、shell 数组的用法

2.1 声明数组

2.1.1 普通数组

2.1.2 关联数组

2.2 定义数组

2.3 读取数组信息

2.3.1 获取数组长度

2.3.2 获取数组列表

2.3.3 读取下标赋值

2.3.4 读取数组下标

2.4 遍历数组

2.5 元素的切片

2.6 元素的临时替换

2.7 删除数组

3、数组最值

3.1 数组的最大值

3.2 数组的最小值

3.3 随机数组的最大最小值

4、冒泡排序

5、随机点名


一、shell函数

1、shell函数的概念

在shell脚本中,函数是一组被命名的命令序列,可以在脚本中多次调用。

使用函数可以将一段常用的代码逻辑封装起来,提高代码的可读性和重用性

函数的组成:函数名和函数体

帮助:help function

2、shell函数的用法

先定义函数,再调用函数

2.1 定义函数

#定义函数方法一:

function   函数名 {
	命令序列
}
#定义函数方法二:

函数名 ()   {
	命令序列
}
#定义函数方法三

function 函数名 () {
	命令序列
}

 2.2 调用函数

#在定义函数后添加函数名,即调用函数

函数名

shell脚本基础之函数与数组详解_第1张图片

shell脚本基础之函数与数组详解_第2张图片

2.3 函数作用范围

2.3.1 调用函数的范围

函数调用虽然可以出现在脚本的任何位置,但前提必须是在调用之前已经定义了相应的函数

shell脚本基础之函数与数组详解_第3张图片

 2.3.2 全局作用域和局部作用域

局部作用域:函数内部使用local关键字声明的变量默认为局部变量,只在函数内部有效。这意味着函数内的变量不会影响到函数外部的同名变量,也不会被函数外部的代码访问到

#local关键字用于声明局部变量

shell脚本基础之函数与数组详解_第4张图片

全局作用域:如果在函数内部没有使用local关键字声明变量,则该变量默认将成为全局变量,在整个脚本中都可见和访问。全局变量可以在函数内部创建,并且可以在函数内部和外部使用

函数在Shell脚本中仅在当前Shell环境中有效,而Shell脚本中变量默认全局有效

shell脚本基础之函数与数组详解_第5张图片

shell脚本基础之函数与数组详解_第6张图片

3、 函数返回值

3.1 系统默认的返回值

#检测输入的ip地址是否符合规范
#!/bin/bash

IPADDRESS () {
read -p "请输入IP地址: " ip_address

# 定义IP地址的正则表达式模式
ip_pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"

# 使用正则表达式进行匹配
if [[ $ip_address =~ $ip_pattern ]]; then
    echo "IP地址格式正确"
else
    echo "IP地址格式错误"
fi
}

IPADDRESS

shell脚本基础之函数与数组详解_第7张图片

 注:

函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码

系统默认只要能执行脚本,无论脚本使用是否出错,使用$?特殊变量获取返回值都是0值

如果想通过返回值向调用者提供错误或正确的结果,就需要使用return语句来指定返回值

3.2 return语句

使用return语句来指定函数的返回值。可以将任意整数值作为返回值,但退出状态码必须是0~255,超出时值将为除以256取余 

通常用非零值表示错误或异常情况,而零表示成功或正常情况

shell脚本基础之函数与数组详解_第8张图片

4、函数传参

函数传参是指将参数传递给一个函数来供函数内部使用

当你定义一个函数时,可以在函数名后的括号内指定参数列表。这些参数将被视为函数的输入,并且可以在函数体内使用

函数传参的目的是让函数能够接受外部提供的数据或信息,以便在函数内部进行处理和操作。通过传递参数,可以使函数更加灵活和通用,可以根据不同的输入执行相同的操作

shell脚本基础之函数与数组详解_第9张图片

shell脚本基础之函数与数组详解_第10张图片

5、查看函数列表

declare  -F               #查看当前已定义的函数名

declare  -f               #查看当前已定义的函数定义

declare  -f   函数名      #查看当前已定义的函数名定义

declare  -F   函数名      #查看指定当前已定义的函数名

shell脚本基础之函数与数组详解_第11张图片

6、删除函数

unset 函数名            #删除定义过的函数

shell脚本基础之函数与数组详解_第12张图片

7、 函数递归

函数递归是指函数调用自身的过程。递归函数可以通过重复调用自身来解决复杂的问题,将大问题分解成更小的子问题,并通过递归调用来解决这些子问题

7.1 函数递归死循环

函数递归指的是在函数内部调用自身的过程,如果不正确使用,函数递归可能会导致死循环,即函数无限地调用自身,直到耗尽系统资源或达到某个限制

7.1.1 模拟死循环
[root@localhost ~]# wx () { echo $i;echo "run fast";let i++;wx; }
[root@localhost ~]# wx

shell脚本基础之函数与数组详解_第13张图片

7.1.2 fork炸弹

fork 炸弹是一种恶意程序,它的内部是一个不断在 fork 进程的无限循环,实质是一个简单的递归程序

由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源 

[root@localhost ~]#bomb() { bomb | bomb & }; bomb
[root@localhost ~]# :(){ :|:& };:

shell脚本基础之函数与数组详解_第14张图片

7.2 阶乘

阶乘是一个正整数的乘积,从该正整数开始递减,直到1。通常用符号"!"表示。例如,n的阶乘可以表示为n!,计算方式为n! = n * (n-1) * (n-2) * ... * 3 * 2 * 1。其中,0的阶乘定义为1

方法一:利用函数递归法求阶乘

使用函数递归来计算阶乘,可以通过重复调用自身来解决阶乘这个复杂的问题

#接受一个参数 $num,表示要计算阶乘的数。函数内部使用条件语句判断基本情况,即当输入的数小于等于1时,直接返回1。否则,它会递归地调用自身来计算$num-1的阶乘,并将结果与$num相乘,然后返回结果

#!/bin/bash
jc () {
read -p "请输入一个正整数:" num
if [ $num -eq 1 ];then
echo 1
else
local temp=$[$num-1]
local result=`jc $temp`
echo $[$num*result]
fi
}
jc $num
bash $0

 方法二:利用for循环求阶乘

#!/bin/bash
read -p "请输入一个正整数:" num
sum=1
i=1
for i in `seq $num`
do
let sum=$[sum*i]
done
echo $sum
bash $0

shell脚本基础之函数与数组详解_第15张图片

注:

基本情况:递归函数必须包含一个基本情况,即函数停止调用自身的条件。如果没有基本情况,递归函数将无限循环下去,导致栈溢出

递归调用:在函数内部,通过调用相同的函数来实现递归。递归调用必须在满足基本情况之前发生,以确保递归能够终止

二、shell数组

1、shell 数组的概念

在Shell脚本中,数组是一种特殊的变量类型,用于存储一系列的值(元素),你可以使用括号来创建和初始化数组

变量和数组:

  • 变量:用一个固定的字符串,代替一个不固定字符串
  • 数组:用一个固定的字符串,代替多个不固定字符串

数组的类型:

  • 普通数组:只能使用整数作为数组索引
  • 关联数组:可以使用字符串作为数组索引 

数组名和索引:

  • 索引的编号(下标)从0开始,属于数值索引
  • 索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持bash的数组支持稀疏格式(索引不连续)

2、shell 数组的用法

2.1 声明数组

2.1.1 普通数组

普通数组是一系列按照索引顺序排列的元素集合。在shell脚本中,普通数组的索引从0开始。可以通过索引来访问数组中的元素

#申明普通数组,shell脚本默认普通数组,可以不使用命令申明直接使用普通数组
declare -a 数组名           
2.1.2 关联数组

关联数组是根据键值对存储的数组,也被称为字典或哈希表。在shell脚本中,关联数组的键可以是任意字符串,而不仅仅是数字。可以通过键来访问数组中的值

#申明关联数组,使用关联数组前必须使用命令申明
declare -A array_name 

shell脚本基础之函数与数组详解_第16张图片

2.2 定义数组

方法一:一次赋值全部元素

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

shell脚本基础之函数与数组详解_第17张图片


方法二:一次只赋值一个元素(为了方便修改或追加元素)

数组名[0]="value1"

数组名[1]="value2"

数组名[2]="value3"
……………………………

shell脚本基础之函数与数组详解_第18张图片

shell脚本基础之函数与数组详解_第19张图片

方法三:综合方法一和方法二,赋值特定元素

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


方法四:元素赋值给列表,引用列表加入组

变量名="value0  value1 value2 value3 ...... "

数组名= $变量名

shell脚本基础之函数与数组详解_第20张图片

shell脚本基础之函数与数组详解_第21张图片


方法五:交互式

read  -a  数组名

shell脚本基础之函数与数组详解_第22张图片

2.3 读取数组信息

2.3.1 获取数组长度
#在数组前添加#,获取数组长度
[root@localhost data]#echo ${#a[@]}
[root@localhost data]#echo ${#a[*]}

shell脚本基础之函数与数组详解_第23张图片

2.3.2 获取数组列表
[root@localhost data]#echo ${a[@]}
[root@localhost data]#echo ${a[*]}

shell脚本基础之函数与数组详解_第24张图片

2.3.3 读取下标赋值
[root@localhost data]#echo ${a[1]}
[root@localhost data]#echo ${a[2]}

shell脚本基础之函数与数组详解_第25张图片

 2.3.4 读取数组下标
[root@localhost data]#echo ${!a[@]}
[root@localhost data]#echo ${!a[*]}

shell脚本基础之函数与数组详解_第26张图片

拓展:

不知道数组的下标,如何追加元素?

#使用数组总长度为下标进行赋值
[root@localhost data]#a[${#a[@]}]=6

shell脚本基础之函数与数组详解_第27张图片

2.4 遍历数组

遍历数组意味着逐个访问数组中的元素,这通常用于对数组中的每个元素执行相同的操作,比如打印它们或者进行某种计算

#!bin/bash
a=(10 20 30 40 50)
for i in ${a[@]}    #挨个赋值,循环五次                
do
echo i=$i               
done

shell脚本基础之函数与数组详解_第28张图片

2.5 元素的切片

可以使用数组切片来获取数组的子集,即从一个数组中获取一部分元素的操作

这种操作允许你创建一个新的数组,其中包含原始数组中特定范围的元素

${a[*]:n:m}        #提取从索引下标n开始的m个元素

${a[*]:n}          #提取从索引下标n开始的所有元素

shell脚本基础之函数与数组详解_第29张图片

2.6 元素的临时替换

echo ${数组名[@]/原始字符/替换字符}    #只是象征性的更换,实际并没有改变原有内容

shell脚本基础之函数与数组详解_第30张图片

 2.7 删除数组

unset  数组名       #删除数组

shell脚本基础之函数与数组详解_第31张图片

unset 数组名[下标]      #删除指定的数组元素

shell脚本基础之函数与数组详解_第32张图片

3、数组最值

3.1 数组的最大值

先定义了一个包含一些整数的数组(交互输入)。然后,假设数组的第一个元素是最大值。接下来,我们使用for循环遍历数组中的每个元素,并将其与当前的最大值进行比较。如果当前元素大于最大值,则更新最大值。最后,打印出最大值

循环次数小于数组长度(即小于数值元素个数,比较n-1次),每次加1

#!/bin/bash
read -p "请输入数组的整数值并以空格隔开:" num
a=($num)
l=${#a[@]}
max=${a[0]}
for ((i=0;i<$l;i++))
do
  if [[ $max -lt ${a[$i+1]} ]];then
  max=${a[$i+1]}
  fi
done
echo "最大值为:$max"

3.2 数组的最小值

先定义了一个包含一些整数的数组(交互输入)。然后,假设数组的第一个元素是最小值。接下来,我们使用for循环遍历数组中的每个元素,并将其与当前的最小值进行比较。如果当前元素小于最小值,则更新最小值。最后,打印出最小值

循环次数小于数组长度(即小于数值元素个数,比较n-1次),每次加1

#!/bin/bash
read -p "请输入数组的整数值并以空格隔开:" num
a=($num)
l=${#a[@]}
min=${a[0]}
for ((i=0;i<$l-1;i++))
do
  if [[ $min -ge ${a[$i+1]} ]];then
  min=${a[$i+1]}
  fi
done
echo "最小值为:$min"

3.3 随机数组的最大最小值

首先生成一个包含10个随机整数的数组。然后,通过遍历数组,使用两个变量maxmin来记录当前的最大值和最小值。最后,打印出最大值和最小值

#!/bin/bash
for i in {0..10}
do
  a[$i]=$RANDOM
  [ $i -eq 0 ] && min=${a[0]} && max=${a[0]}
  [ ${a[$i]} -gt $max ] && max=${a[$i]}
  [ ${a[$i]} -lt $max ] && min=${a[$i]}
done
echo ${a[@]}
echo "最大值为:$max"
echo "最小值为:$min"

4、冒泡排序

  • 数组排序算法

冒泡排序类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动

  • 冒号排序基本思想

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

  • 算法思路

冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般循环次数小于数组长度(即小于数值元素个数,比较n-1次),每次加1。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置对比和交换次数随排序轮数而减少

第一轮比较(n个数):找出最大值,将最大值放到最后,比n-1次

第二轮比较(n-1个数):找出最大值,将最大值放到最后,比n-2次

第三轮比较(n-2个数):找出最大值,将最大值放到最后,比n-3次

……

最后一轮比较(最后两个数):找出最大值,将最大值放到最后,比1次

#!/bin/bash
a=(1 5 2 0 6 4 8)
l=${#a[@]}
for ((i=1;i<$l;i++))                   #轮次循环
do
  for ((j=0;j<$l-i;j++))               #相邻数对比循环
  do    
    first=${a[$j]}                     #定义第一个数
    k=$[j+1]                           #定义变量代表后一个数
    second=${a[$k]}                    #给第二个数赋值
      if [ $first -gt $second ];then  
      temp=$first                      #如果第一个数大于第二个数,第一个数作为最大临时值    
      a[$j]=$second                    #第二个数的值赋给第一个数
      a[$k]=$temp                      #临时值赋给第二个数,完成位置调换
      fi                
  done  
done
echo ${a[@]}

冒泡排序随机十个数

#!/bin/bash
 
for i in {0..10}
do
  a[$i]=$RANDOM
done
 
l=${#a[@]}
for ((i=1;i

5、随机点名

要实现随机点名的功能,可以使用Shell脚本中的随机数生成函数和数组来实现

#!/bin/bash
namefile="/data/name.txt"
linenum=$(sed -n '$=' $namefile)
while :
do
 clear
 tmp=$(sed -n "$[RANDOM%linenum+1]p" $namefile)
 echo -e "\E[32m  随机点名(ctrl+c停止): \E[0m"
 echo -e "\E[32m########################\E[0m"
 echo -e "\E[32m#                      #\E[0m"
 echo -e "\E[32m          $tmp          \E[0m"
 echo -e "\E[32m#                      #\E[0m"
 echo -e "\E[32m########################\E[0m"
 sleep 0.03
done

shell脚本基础之函数与数组详解_第33张图片

你可能感兴趣的:(linux,运维,服务器)