Shell脚本——函数的使用

一、函数

1.函数的作用

定义较为复杂的但是需要重复使用的内容以便再次使用可以直接调用函数节约时间,提高效率

在编写脚本时,有些脚本可以反复使用,可以调用函数来解决,语句块定义成函数约等于别名

函数定义:封装的可重复利用的具有特定功能的代码

使用函数可以避免代码重复,增加可读性,简化脚本
使用函数可以将大的工程分割为若干小的功能模块,代码的可读性更强

函数使用步骤

①首先是定义函数

②其次是调用函数(注意:若定义完成不调用则函数无效)

③查看系统限制所有函数:declare -F

④查看函数定义详细内容:declare -f  函数名

⑤删除函数 :unset  函数名

函数使用方法:

1. 定义函数  2. 再引用函数

2.函数的基本格式

第一种:

[function] 函数名 (){
	命令序列
	[return x]         #使用return或者exit可以显式的结束函数
}

第二种:

一般用这一种

函数名(){
	命令序列
}

第三种:

​
function  函数名 {

函数内容

}

​

实验1:用函数 判断操作系统是centos 还是ubuntu

#!/bin/bash

os () {
if grep -q centos /etc/os-release ;then
echo "操作系统是centos"
elif grep -q ubuntu /etc/os-release ;then
echo "操作系统是ubuntu"
else
echo "操作系统按不支持"
fi
}

os

Shell脚本——函数的使用_第1张图片

判断操作系统是centos 还是ubuntu

Shell脚本——函数的使用_第2张图片

实验2:建立专门的函数文件

 接着上面继续, 这是在data下

Shell脚本——函数的使用_第3张图片

然后调用就可以了

Shell脚本——函数的使用_第4张图片

我们模拟下在 ~家目录下:

Shell脚本——函数的使用_第5张图片

Shell脚本——函数的使用_第6张图片

color ()[
red="echo -eE[31m"
green="echo -e E[32m'
end="\E[Om"

3.注意事项

  1. 直接写 函数中调用函数 直接写函数名

  2. 同名函数 后一个生效

  3. 调用函数一定要先定义

  4. 每个函数是独立

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

Shell脚本——函数的使用_第7张图片

4.删除函数

删除函数 :unset  函数名

Shell脚本——函数的使用_第8张图片

5.函数的返回值

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

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

退出状态码必须是0~255,超出时值将为除以256取余

return
函数的退出状态码:
默认取决于函数中执行的最后一条命令的退出状态码

自定义退出状态码,其格式为:
return 从函数中返回,用最后状态命令决定返回值
return 0无错误返回
return 1-255 有错误返回

return 只能用在函数中

#!/bin/bash

ip () {
read -p "请输入一个ip地址: "  host
[[ "$host"  =~  ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || { echo "ip 地址不合法" ;return
 1; }
}

ip

实验1:判断输入IP地址正确与否

Shell脚本——函数的使用_第9张图片

Shell脚本——函数的使用_第10张图片

实验2:判断是否为管理员用户登录

#!/bin/bash
user () {
if [ $USER = root ]
 then echo "这是管理员用户"
else
echo "这不是管理员用户"
return 1
fi
}
user

Shell脚本——函数的使用_第11张图片

Shell脚本——函数的使用_第12张图片

6.函数的传参数

实验:

Shell脚本——函数的使用_第13张图片

我们修改脚本,模式换下位置:

Shell脚本——函数的使用_第14张图片

一般不会这样的,按着顺序来下哦

7.使用函数文件

我们可以新建一个专门存放函数的文件 (参考标题2)

8.函数的作用范围

函数在shell脚本中仅在当前的shell环境中有效

shell脚本中函数的变量默认全局有效

将变量限定在函数内部使用local命令

Shell脚本——函数的使用_第15张图片

Shell脚本——函数的使用_第16张图片

9. 函数递归

函数调用自己本身的函数,必须要有结束函数的语句,防止死循环

阶乘

阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语

一个正整数的阶乘 (factorial) 是所有小于及等于该数的正整数的积,并且0和1的阶乘为1,自然数n的阶乘写作n!
n!=1x2x3x...xn

阶乘亦可以递归方式定义: 0!=1,n!=(n-1)!xn
n!=n(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!

! 表示阶乘

0!=1

1=1X0!

2!=2x1!

3!=3x2!

4!=4x3!

实验1:用 for 循环写阶乘
​
#!/bin/bash
read -p "请输入一个正整数:" num
sum=1
for i in `seq $num`
do
let sum=$[i*sum]
done
echo "阶乘结果是" $sum

​

Shell脚本——函数的使用_第17张图片

实验2:用函数写阶乘
​
#!/bin/bash

fact () {

if [  $1 -eq  1  ]
then
echo 1
else
local temp=$[$1-1]
local result=`fact $temp`
echo "$[$1 * result]"

fi
}

fact $1

​

Shell脚本——函数的使用_第18张图片

Shell脚本——函数的使用_第19张图片

帮助理解下,如图:

Shell脚本——函数的使用_第20张图片

实验:使用函数一键安装nginx脚本

先去nginx官网,下载,鼠标右击复制连接

nginx.org非盈利组织,开源不一定免费 ,只有新机器才需要安装

Shell脚本——函数的使用_第21张图片

可以过滤下CPU

Shell脚本——函数的使用_第22张图片

#!/bin/bash
cpu=`lscpu |grep "CPU(s)"|awk '{print$2}'|head -n1`
read -p "输入安装目录(绝对路径):" dir
cd /data
wget http://nginx.org/download/nginx-1.18.0.tar.gz  &>/dev/null
tar xf nginx-1.18.0.tar.gz
yum -y install gcc  gcc-c++  pcre-devel openssl-devel zlib-devel openssl  openssl-devel &>/dev/null
cd /data/nginx-1.18.0
./configure --prefix=$dir &>/dev/null
make -j $cpu  &>/dev/null
make install  &>/dev/null
 if [ $? -eq 0 ]
 then
 echo "安装成功"
 else
 echo "安装失败"
 fi

Shell脚本——函数的使用_第23张图片

Shell脚本——函数的使用_第24张图片

二、数组

1.前言

将全班学生定义成一个变量,无法使用普通变量。

  • 普通数组

  • 关联数组

变量和属组

  • 变量:存储单个元素的内存空间

  • 数组:存储多个元素的连续的内存空间,相当于多个变量的集合

数组名和索引

  • 索引的编号从0开始,属于数值索引

  • 索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持

  • bash的数组支持稀疏格式(索引不连续)

2.shell数组的定义

数组中可以存放多个值,Bash Shell 只支持一维数组(不支持多维数组)

数组元素的下标由 0 开始

Shell 数组用括号来表示,元素用"空格"符号分割开

在shell语句中,使用、遍历数组的时候,数组格式要写成 ${arr[@]} 或 ${arr[*]}

3.定义数组方法

方法一:

数组名=(value1 value2 ... valuen)
[root@zzh data]#a=(1 2 3 4 5)
[root@zzh data]#echo ${a[@]}
1 2 3 4 5

Shell脚本——函数的使用_第25张图片

方法二:

数组名=([0]=value0 [1]=value0 [2]=value0 ...)
[root@zzh data]#b=([0]=1 [1]=2 [2]=3 [3]=4 [4]=5)
[root@zzh data]#echo ${b[@]}
1 2 3 4 5

Shell脚本——函数的使用_第26张图片

方法三:

数组名[0]="value"
数组名[1]="value"
数组名[2]="value"
 
[root@localhost data03]#c[0]=1
[root@localhost data03]#c[1]=2
[root@localhost data03]#c[2]=3
[root@localhost data03]#c[3]=4
[root@localhost data03]#echo ${c[@]}
1 2 3 4

Shell脚本——函数的使用_第27张图片

也可以给下标赋值,采用这种方式再添加就可以了

方法四:

列表名="value0 value1 value2 ..."
数组名=(S列表名)
[root@zzh data]#a="10 20 30 40 50"
[root@zzh data]#echo $a
10 20 30 40 50
[root@zzh data]#b=( $a )
[root@zzh data]#echo ${b[@]}
10 20 30 40 50
[root@zzh data]#

Shell脚本——函数的使用_第28张图片

方法五:

Shell脚本——函数的使用_第29张图片

4.获取数组的数据列表

echo ${数组名[*]}
echo ${数组名[@]}

普通索引(调用普通数组)

Shell脚本——函数的使用_第30张图片

实验:使用函数 随机点名

#!/bin/bash
a=(xm xh xl xw lzl zs)
num=`echo $[RANDOM%6]`
echo ${a[$num]}

Shell脚本——函数的使用_第31张图片

实验:使用函数 随机点名                  (效果更好)

[root@zzh data]#vim dm.sh 
#!/bin/bash
namefile="/data/name.txt"
linenum=$(sed -n '$=' $namefile)
while :
do
clear
tmp=$(sed -n "$[RANDOM%linenum+1]p" $namefile)
echo -e "\033[31m            随机点名(ctrl+c 停止):                  \033[0m"
echo -e "\033[31m####################################################\033[0m"
echo -e "\033[31m##                                                ##\033[0m"
echo -e "\033[31m##                                                ##\033[0m"
echo -e "\033[31m##                     $tmp                       ##\033[0m"
echo -e "\033[31m##                                                ##\033[0m"
echo -e "\033[31m##                                                ##\033[0m"
echo -e "\033[31m####################################################\033[0m"
sleep 0.5
done
[root@zzh data]#bash dm.sh

Shell脚本——函数的使用_第32张图片

Shell脚本——函数的使用_第33张图片

Shell脚本——函数的使用_第34张图片

Shell脚本——函数的使用_第35张图片

5.数组的数据类型

  • 数值类型

  • 字符类型:使用" "或’ '定义

[root@zzh data]#a=(1 2 3 4 5);echo ${a[@]}
1 2 3 4 5
[root@zzh data]#a=(a 1 2 apple);echo ${a[@]}
a 1 2 apple
[root@zzh data]#

6.获取数组下标对应的值

数组名和索引

  • 索引的编号从0开始,属于数值索引

  • 索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持

  • bash的数组支持稀疏格式(索引不连续)Shell脚本——函数的使用_第36张图片

数组名=(元素0  元素1  元素2  ……)					定义数组
echo ${数组名[索引值]}							输出数组索引值对应的元素,索引值为从0开始


echo ${#数组名[*]} 
echo ${#数组名[@]} 
echo ${!数组名[@]}  #显示下标
 
 

Shell脚本——函数的使用_第37张图片

7.声明数组

#普通数组可以不事先声明,直接使用
declare  -a  数组名
 
#关联数组必须先声明,再使用
declare  -A  数组名

普通数组可以不事先声明,直接使用

关联数组必须先声明,再使用

(关联数组)关联索引

Shell脚本——函数的使用_第38张图片

8.获取数组长度

echo ${#数组名[*]}  #显示下标总个数
echo ${#数组名[@]}  #显示下标总个数
echo ${!数组名[@]}  #显示下标
 
 
echo ${数组名[索引值]}			输出数组索引值对应的元素,索引值为从0开始

获取数组长度即数组下标的总个数 

Shell脚本——函数的使用_第39张图片

想追加一个数,但是不知道下标是多少,我们就把它的长度显示出来,在追加

Shell脚本——函数的使用_第40张图片

下一个数的下标,刚好是下一个值 例如 下标5 数值是60

三、数组的常用操作

1.遍历数组

#!/bin/bash
a=(1 2 3 4 5 6)
for i in ${a[@]}
do
echo i=$i
done

Shell脚本——函数的使用_第41张图片

Shell脚本——函数的使用_第42张图片

2.数组切片

Shell脚本——函数的使用_第43张图片

[root@zzh data]#a=(10 20 30 40 50 60) #定义数组
[root@zzh data]#echo ${a[@]}   #输出整个数组
10 20 30 40 50 60
[root@zzh data]#echo ${a[@]:3:2}  #跳过前3个,往后取2个
40 50
[root@zzh data]#echo ${a[@]:3}
40 50 60
[root@zzh data]#echo ${a[@]:3:4} #跳过前3个,取后4个(由于这没定义,没显示)
40 50 60
[root@zzh data]#echo ${a[@]:2:4}
30 40 50 60
[root@zzh data]#

Shell脚本——函数的使用_第44张图片

3.数组替换

${数组名[@或*]/查找字符/替换字符) 并不会替换数组原有内容

要实现改变原有数组,可通过重新赋值实现

Shell脚本——函数的使用_第45张图片

4.数组删除

Shell脚本——函数的使用_第46张图片

Shell脚本——函数的使用_第47张图片

四、求数组中的最大值和最小值

实验1:求数组中的最大值

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

Shell脚本——函数的使用_第48张图片

  1. a=($num):将输入的数字数组存储在名为 a 的数组变量中。
  2. max=${a[0]}:将数组中的第一个元素赋值给变量 max,作为初始的最大值。
  3. l=${#a[@]}:获取数组 a 的长度,并将其保存在变量 l 中。
  4. for ((i=0; i<$l; i++)):循环遍历数组中的元素,从索引 0 开始,比的次数小于循环次数
  5. if [[ $max -lt ${a[$i+1]} ]]:检查当前的最大值是否小于下一个元素。
  6. then max=${a[$i+1]}:如果下一个元素大于当前的最大值,则更新最大值为下一个元素的值。
  7. echo "最大值为: $max":打印出计算得到的最大值。

Shell脚本——函数的使用_第49张图片

实验2:求数组中的最小值

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

Shell脚本——函数的使用_第50张图片

实验3:求数组中的最大值和最小值

#!/bin/bash
for i in {0..9}
do
  a[$i]=$RANDOM
   [ $i -eq 0  ] &&  min=${a[0]}  &&  max=${a[0]}
   [ ${a[$i]} -gt  $max   ] && max=${a[$i]}
   [ ${a[$i]} -lt  $min   ] && min=${a[$i]}
done

echo  ${a[@]}

echo max=$max
echo min=$min

Shell脚本——函数的使用_第51张图片

Shell脚本——函数的使用_第52张图片

五、冒泡排序

数组排序算法:冒泡排序类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。
基本思想:冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

算法思路:冒泡算法由双层循环实现,其中外部循环用于控制排序轮数一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置对比和交换次数随排序轮数而减少。

score=(77 13 91 56 88)
 
两两对比,第1个和第2个比,小的值到前面,大的值到后面。
以此类推。第2个和第3个比,第3个和第4个比,第4个和第5个比
 
------------第一轮------------
77 13 91 56 88 第一次对比 数组长度-1 第一轮比较往后值, 最大值为91 
13 77 91 56 88 第二次对比 
13 77 91 56 88 第三次对比 
13 77 56 91 88 第四次对比 
13 77 56 88 91
------------第二轮------------
13 77 56 88 91 第一次对比 数组长度-1第二轮比较往后,第二大的数字88 
13 77 56 88 91 第二次对比 
13 56 77 88 91 第三次对比 
13 56 77 88 91
------------第三轮-----------
13 56 77 88 91 第一次对比 数组长度-1第三轮比较往后,第三大的数字77 
13 56 77 88 91 第二次对比 
13 56 77 88 91
------------第四轮-----------
13 56 77 88 91 第一次对比 数组长度-1第四轮比较往后,第四大的数字56 
13 56 77 88 91

例如:

Shell脚本——函数的使用_第53张图片

实验:冒泡排序 

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

Shell脚本——函数的使用_第54张图片

解释如下:

Shell脚本——函数的使用_第55张图片​​​​​​​

内循环是比较大小和位置互换的,外循环是比轮次的

Shell脚本——函数的使用_第56张图片

#!/bin/bash
array=(98 76 24 100 35 3)
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[@]}"

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