Shell函数应用与数组排序

目录

一、函数

1. 概述

2. 定义调用函数

3. 查看函数列表

4. 删除函数

5. 建立函数文件并添加颜色

6. 函数返回值

7. 函数传参 

8. 函数变量的作用范围

9. 函数递归

9.1 模拟死循环

9.2 阶乘 

二、数组

1. 数组的定义

2. 声明数组 

3. 定义数组 

4. 获取数组信息

4.1 获取数组长度

4.2 获取数据列表

4.3 读取下标赋值

4.4 读取下标

5. 数组遍历

6. 元素的切片

7. 元素的临时替换

8. 数组删除

9. 数组最值 

9.1 固定数组最大值 

9.2 随机数组最大最小值

10. 数组冒泡排序


一、函数

1. 概述

在Shell脚本中,函数是一种可重复使用的代码块,可以在脚本中多次调用。函数可以接受参数,执行一些操作,并且可以返回一个值。函数的定义和调用都遵循一定的语法规则。需要注意的是函数必须先定义才可以使用。

2. 定义调用函数

【1】
function 函数名 {
	命令序列                #函数要实现的功能代码
}

【2】
函数名() {
	命令序列                #函数要实现的功能代码
}

【3】
function 函数名 (){
	命令序列                #函数要实现的功能代码
}

示例:

[root@localhost ~]# vim hello.sh 
#!/bin/bash 
function hello {                     #定义函数名为hello,它不接受任何参数
    echo "Hello, World!"             
}
hello                                #调用函数
[root@localhost ~]# bash hello.sh    #执行的操作是输出字符串"Hello, World!" 
Hello, World!

3. 查看函数列表

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

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

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

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

4. 删除函数

[root@localhost ~]# hello (){ echo "Hello, World"; }  #定义函数
[root@localhost ~]# hello                             #调用函数
Hello, World
[root@localhost ~]# unset hello                       #unset func_name
[root@localhost ~]# hello
bash: hello: 未找到命令...

5. 建立函数文件并添加颜色

创建一个存储函数的文件,可以在其中定义需要的函数,使用时运行脚本即可。

示例:检测当前系统linux版本

[root@localhost ~]# cat func
#!/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
}

color () {                             #定义函数
red="echo -e \E[31m"
green="echo -e \E[32m"
end="\E[0m"
}

[root@localhost ~]# vim os.sh
#!/bin/bash
. /root/func
os                                     #调用函数
color                                  #调用函数
$green安装成功$end                      #调用变量
[root@localhost ~]# bash os.sh 
centos
安装成功                                #文字呈现绿色

6. 函数返回值

函数的返回值可以在调用函数时被捕获并使用。通常可以使用赋值操作符将函数的返回值保存在变量中,以便后续使用。赋值范围0~255。 return 100提前退出函数并指定返回值100,即exit 100。

示例:

[root@localhost ~]# num () { [ 1 -eq 0 ] || echo "1不等于0"; };echo $?
0
[root@localhost ~]# num () { [ 1 -eq 0 ] || echo "1不等于0;return 1};echo $?
1
#return 1指定函数返回值

应用:判断IP地址是否合法

[root@localhost ~]# vim os.sh
ip () {
read -p "请输入ip:" host
  [[ $host =~  ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || echo "${host}不合法";return 1;
}
ip

[root@localhost ~]# bash 1.sh 
请输入ip:192.168.190.1000
192.168.190.1000不合法
[root@localhost ~]# echo $?      #如果不修改函数返回值,即使ip不合法$?依然可以返回0
1

使用原则:

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

7. 函数传参 

函数传参是指将参数传递给一个函数来供函数内部使用。当你定义一个函数时,可以在函数名后的括号内指定参数列表。这些参数将被视为函数的输入,并且可以在函数体内使用。函数传参的目的是让函数能够接受外部提供的数据或信息,以便在函数内部进行处理和操作。通过传递参数,可以使函数更加灵活和通用,可以根据不同的输入执行相同的操作。

[root@localhost ~]# vim c.sh
#!/bin/bash
h () {
echo "参数是:"$1 $2 $3
}
h $1 $2 $3
[root@localhost ~]# bash c.sh 1 2 3
参数是:1 2 3

特别情况介绍:

[root@localhost ~]# vim c.sh
#!/bin/bash
h () {
echo "参数是:"$1 $2 $3
}
h $2 $1 $3
[root@localhost ~]# bash c.sh 1 2 3
参数是:2 1 3

h $2 $1 $3中:对于函数而言依然是$1 $2 $3;对于脚本位置变量所对应的是2 1 3

8. 函数变量的作用范围

[root@localhost ~]# name=zhou
[root@localhost ~]# 
[root@localhost ~]# name=zhang
[root@localhost ~]# func1 () { name=li;echo $name; }   #函数的变量会影响当前环境
[root@localhost ~]# func1
li
[root@localhost ~]# echo $name
li
[root@localhost ~]# name=zhang
[root@localhost ~]# func1 () { local name=li;echo $name; }  #local,锁定在本地
[root@localhost ~]# func1
li
[root@localhost ~]# echo $name
zhang

9. 函数递归

递归是指一个函数调用自身的过程,需要注意的是,递归函数可能会导致性能问题,因为每次调用都会创建一个新的函数帧。

9.1 模拟死循环

死循环一直调用自身开进程,模拟病毒

[root@localhost ~]# func () { echo $i;echo "run fast";let i++;func; }
[root@localhost ~]# func

 fork炸弹

bomb() { bomb | bomb & }; bomb

9.2 阶乘 

阶乘是一个自然数与小于它的自然数的乘积。通常用感叹号表示,例如n的阶乘用n!表示,定义为n!=n*(n-1)(n-2)...321。

① for循环写法

#!/bin/bash
read -p "请输入一个正整数:"num
sum=1
i=1
for i in `seq $num`
do
let sum=$[sum*i]
done
echo $sum 
[root@localhost ~]# bash for.sh 
请输入一个正整数:5
120

② 函数写法

#!/bin/bash
fact () {
if [ $1 -eq 1 ];then
echo 1
else
local temp=$[$1-1]
local result=`fact $temp`
echo $[$1*result]
fi
}
read -p "请输入一个正整数:" num
fact $num
[root@localhost ~]# bash h.sh
请输入一个正整数:5
120

原理:当输入数字时,和1比较,如果等于则输出1;如果不等于,求比自己小1数字的阶乘;如果依然不等于1,则继续求比自己小1数字的阶乘,直到等于1为止。最后根据上一个数字的阶乘结果与自己相乘得到自己的阶乘。比如5的阶乘计算流程:知道1的阶乘,计算2的阶乘为2*1;知道2的阶乘,计算3的阶乘为3*2;知道3的阶乘,计算4的阶乘为4*6;知道4的阶乘,计算5的阶乘为5*24。

二、数组

1. 数组的定义

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

变量和数组:

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

数组的类型:

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

数组名和索引:

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

2. 声明数组 

declare -a 数组名:申明普通数组,可以不申明直接使用

declare -A 数组名:申明关联数组,必须要申明

[root@localhost ~]# declare -A lisi           #申明关联数组
[root@localhost ~]# lisi[people]=3
[root@localhost ~]# lisi[address]=china
[root@localhost ~]# lisi[mail]=qq
[root@localhost ~]# echo ${lisi[people]}      #调用
3
[root@localhost ~]# echo ${lisi[mail]}
qq
[root@localhost ~]# echo ${lisi[address]}
china

3. 定义数组 

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

[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# echo ${a[@]}
1 2 3 4 5

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

[root@localhost ~]# b[0]=6
[root@localhost ~]# b[1]=7
[root@localhost ~]# b[2]=8
[root@localhost ~]# echo ${b[@]}
6 7 8

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

[root@localhost ~]# c=([0]=9 [1]=10 [2]=11)
[root@localhost ~]# echo ${c[@]}
9 10 11

方法四:元素赋值给变量,引用变量加入组

[root@localhost ~]# num=`seq 12 15`
[root@localhost ~]# d=$num
[root@localhost ~]# echo ${d[@]}
12 13 14 15

方法五:交互式,基本格式read -a 数组名

[root@localhost ~]# read -a num
16 17 18
[root@localhost ~]# echo ${num[@]}
16 17 18

4. 获取数组信息

4.1 获取数组长度

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

4.2 获取数据列表

[root@localhost ~]# echo ${a[*]}
1 2 3 4 5
[root@localhost ~]# echo ${a[@]}
1 2 3 4 5

4.3 读取下标赋值

[root@localhost ~]# echo ${a[1]}
2
[root@localhost ~]# echo ${a[4]}
5

4.4 读取下标

[root@localhost ~]# echo ${!a[*]}
0 1 2 3 4

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

[root@localhost ~]# a[${#a[@]}]=6
[root@localhost ~]# echo ${a[*]}
1 2 3 4 5 6
#下标从0开始,先查询长度,再以长度为下标赋值

5. 数组遍历

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

#!bin/bash
a=(1 2 3 4 5)
for i in ${a[@]}                  #挨个赋值,循环五次
do
echo i=$i               
done
[root@localhost ~]# bash b.sh 
i=1
i=2
i=3
i=4
i=5

6. 元素的切片

可以使用数组切片来获取数组的子集,即从一个数组中获取一部分元素的操作。这种操作允许你创建一个新的数组,其中包含原始数组中特定范围的元素。

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

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

[root@localhost ~]# a=(1 2 3 4 5 6)
[root@localhost ~]# echo ${a[@]:3:2}   #跳过前三个取后两个
4 5
[root@localhost ~]# echo ${a[@]:3}     #跳过前三个
4 5 6

7. 元素的临时替换

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

echo ${数组名[@]} 并不会替换数组原有内容

[root@localhost ~]# a=(1 2 3 4 5 6)
[root@localhost ~]# echo ${a[@]/6/10}
1 2 3 4 5 10
[root@localhost ~]# echo ${a[@]}
1 2 3 4 5 6

8. 数组删除

[root@localhost ~]# a=(1 2 3 4 5 6)
[root@localhost ~]# unset a[5];echo ${a[@]}  #删除指定元素
1 2 3 4 5
[root@localhost ~]# unset a;${a[@]}          #删除整个数组
[root@localhost ~]# 

9. 数组最值 

9.1 固定数组最大值 

求数值最大值:假设第一个数最大,与第下一个数作比较,如果小于第二个数,则第二个数上位“临时最大值”,继续同下一个数比较;如果大于第二个数,则保持“临时最大值”同下一个数做比较。循环次数小于数组长度(即小于数值元素个数,比较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
[root@localhost ~]# bash max.sh
请输入数组值以空格隔开:1 2 7 8 5  
8

9.2 随机数组最大最小值

随机生成10个数值,求最大值和最小值。没有比较时,第一个数既是最大值也是最小值,将其作为临时最大值;如果后面的数大于最大值,后面的数即为最大值;如果后面的数小于最大值,最大值保持不变。

#!/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 $max ] && min=${a[$i]}
done
echo ${a[@]}
echo max=$max
echo min=$min
[root@localhost ~]# bash maxmin.sh
4761 13743 11963 5884 7064 18659 25427 4096 11666 32114
max=32114
min=11666

10. 数组冒泡排序

冒泡排序通过多次遍历数组,比较相邻元素并交换它们的位置,逐渐将较大(或较小)的元素推向数组的末尾。这个过程会重复进行,直到整个数组排序完成。

中心思想:定义两个元素和一个临时变量,如果第一个比第二个大,互换,并把第一个元素值保留在临时变量中;把第二个元素值赋给第一个元素;把临时变量赋给第二个元素。

外循环:从第一轮开始,轮次小于数组长度(比较轮次)

内循环:数组的长度减去轮次(找数)

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

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

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

……

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

#!/bin/bash
a=(1 3 5 2 4 6)
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
[root@localhost ~]# bash mp.sh 
1 2 3 4 5 6
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值