shell 函数与数组

一、Shell函数:


函数的数学表达式
sin   cos   tan     其实就是定义好了计算公式  函数就是一个功能模块,在函数中写好执行的命令即可
使用函数可以避免代码重复,增加可读性, 简化脚本
使用函数可以将大的工程分割为若干小的功能模块,代码的可读性更强

函数使用方法:

  1. 定义函数

  2. 再引用函数

基本格式:

1、 
function 函数名{
   命令序列
}

2、
函数名 (){
   命令序列
}

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

注意事项

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

  2. 同名函数 后一个生效

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

  4. 每个函数是独立

func_name (){
...函数体...
}


[root@localhost ~]#func1 (){ hostname;date;}
#定义函数
[root@localhost ~]#func1
#调用函数
localhost.localdomain
2024年 01月 26日 星期五 23:46:00 CST

#!/bin/bash
h () {
echo "hello"
}
h

1.1 查看函数

declare -F

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

[root@localhost ~]# declare -F
#函数列表
declare -f __HOSTNAME
declare -f __SIZE
declare -f __SLAVEURL
-------------过多省略------------------


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



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

[root@localhost ~]#declare -f test1
test1 () 
{ 
    read -p "请输入一个数字:" num;
    return $[$num*2]
}


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

[root@localhost ~]#declare -F test1
test1

1.2 删除函数

unset 函数名

[root@localhost ~]#func1 (){ hostname;date;}
[root@localhost ~]#func1
localhost.localdomain
2024年 01月 26日 星期五 23:46:00 CST

[root@localhost ~]#unset func1
[root@localhost ~]#func1
bash: func1: 未找到命令...

1.3 函数的返回值

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

通常 $? 表示上一次命令的执行结束是否正确,0 为正确,其它表示错误。echo $?

使用原则:

1. 函数一结束就去返回值,应为$?变量只返回执行的最后一条命令的退出返回码
2. 退出码必须是0-255,超出的值将为除以256取余

【return】
函数的退出状态码:
默认取决于函数中执行的最后一条命令的退出状态码
自定义退出状态码,其格式为:
return 从函数中返回,用最后状态命令决定返回值
return 0 无错误返回
return 1-255 有错误返回


#!/bin/bash
test1 () {
        read -p "请输入一个数字:" num
        return $[$num*2]


}

test1
echo $?

#可以看到返回的结果为 两倍的 num

怎么解决超过 255

#!/bin/bash
test1 () {
        read -p "请输入一个数字:" num
        echo $[$num*2]


}

result=`test1`
echo $result

return 的用法:

user () {

if  [ $USER = root ] 
then
echo "这是管理员用户"
else
echo "这不是管理员用户"
return 1
fi
}

user

1.4 函数的传参数

[root@localhost ~]#vim chuan.sh

#!/bin/bash
sum1 (){
echo $1    #输出第一个位置参数
echo $2    #输出第二个位置参数

}
sum1 $2 $1  #调用函数 并把 输出的第二个位置参数 放在第一个 ,然后把 输出的第一个位置参数 放在第二个 

不加位置变量($1)无法输出。

#如下所示 :abc 是 第一个位置参数 ,bcd 是第二个位置参数
[root@localhost ~]#bash chuan.sh abc bcd
bcd
abc

例子:

脚本 使用函数 判断操作系统类型 ,并安装相应的 httpd 安装包

#!/bin/bash
os (){
 if grep -i -q ubuntu /etc/os-release
 then 
 echo "ubuntu"
 elif  grep -i -q centos /etc/os-release
 then
 echo "centos" 
 else 
 echo "os not support!"
fi
}


if [ `os` = centos ]
then
  yum install httpd -y 
elif [ `os` = ubuntu ]
then
  apt install apache2 -y
else
  echo "os not support!"
fi

1.5 函数的作用范围

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

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

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

[root@localhost opt]# vim demo8.sh
#!/bin/bash
myfun(){
i=8
echo $i    #输出变量
}
myfun   #调用函数

[root@localhost opt]#bash demo8.sh 
8


[root@localhost opt]# vim demo8.sh
#!/bin/bash
myfun(){
i=8
echo $i

}
myfun
echo $i  #输出当前环境的变量i

[root@localhost opt]#bash demo8.sh    #注意 bash 是在子环境里运行脚本
8
8    #可以看到 函数里的变量在当前环境中有效




[root@localhost opt]# vim demo8.sh 
#!/bin/bash
myfun(){
i=8
echo $i

}
i=9       #在调用函数前先定义变量为 9 。
myfun     #调用函数

echo $i    #输出当前环境的变量i
[root@localhost opt]# ./demo8.sh 
8
8
#可以看到 事先定义的变量在调用过函数后发生了改变,已经不再是9了。
#注意 ,在调用函数之前 ,函数里面定义的变量以及命令都不会生效。



[root@localhost opt]# vim demo8.sh 
#!/bin/bash
myfun(){
i=8
echo $i

}
myfun
i=9         #在调用函数后再定义 一次变量。
echo $i

[root@localhost opt]# ./demo8.sh 
8
9
#可以看到 调用函数后更改变量才会有效。

local 命令

[root@localhost opt]# cat demo8.sh 
#!/bin/bash
myfun(){
local i=8     #将变量限定在函数内部使用
echo $i

}
i=9
myfun
echo $i

[root@localhost opt]#bash demo8.sh 
8
9

#因变量被限制在函数内部,所以不会影响事先定义的变量



[root@localhost ~]#name=qian
[root@localhost ~]#func1 () { name=li ; echo $name; }
[root@localhost ~]#func1
li
[root@localhost ~]#echo $name 
li
[root@localhost ~]#name=qian;func1 () { local name=li ;echo $name; };echo $name
#加上local变量即可将变量限制在函数内
qian

1.6 函数文件

我们可以新建一个专门存放函数的文件

[root@localhost ~]#vim mlall   #建立专门的函数文件

#!/bin/bash
lsos () {
if grep -i -q centos /etc/os-release
then
echo "系统是centos"
elif grep -i -q ubuntu /etc/os-release
then
echo "系统是ubuntu"
else
   echo this os is not centos and ubuntu
fi
}


color () {
red="echo -e \E[31m"
green="echo -e \E[32m"
end="\E[0m"
}
#这个不如直接定义变量。

red="echo -e \E[31m"
green="echo -e \E[32m"
end="\E[0m"
#使用方法 ${red}写上你要输出的内容就会改变颜色了${end}

[root@localhost ~]#. mlall  #使用次命令在当前shell环境运行此函数文件。

[root@localhost ~]#lsos
系统是centos

1.7 函数递归

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

阶乘

阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0和1的阶乘为1,自然数n的
阶乘写作n!
n!=1×2×3×...×n
阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n
n!=n(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!

实例:

#谨慎使用此脚本,这可能导致机器死机。

#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ] 
then
echo 1
else
echo $[$1*$(fact $[$1-1])]
 fi
}
fact $1

运行时后面一定要加位置参数



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

递归目录:

function list_files {
for f in `ls $1`
do
   if [ -d "$1/$f" ]
   then
      echo "$2$f"
      list_files "$1/$f" " $2"
   else
       echo "$2$f"
   fi
done
}

list_files "/var/log" ""

 

1.8 数组

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

  • 普通数组

  • 关联数组

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

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

数组名和索引

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

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

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

1.8.1 基础

定义数组格式:

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

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

  3. 列表名="value0 value1 value2 value3 ...... "

    数组名=($列表名)

  4. 数组名[0]="value1"

    数组名[1]="value2"

    数组名[2]="value3"

数组的包括数据类型

  • 数值型

  • 字符型

  • 混合型数值加字符

使用" "或' '定义 用单引号或双引号括起来

关于数组:

[root@localhost ~]# a=(a b c d e f)
#定义数组


如何查看定义的数组?
1、 
[root@localhost ~]#declare -a
declare -a a='([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f")'

2、
[root@localhost ~]#echo ${a[*]}        //*代表所有参数
a b c d e f

[root@localhost ~]#echo ${a[@]}        //@同* 
a b c d e f


如何查看下标?
[root@localhost ~]#echo `echo ${!a[*]}`
0 1 2 3 4 5
#表示(a b c d e f)所在位置



如何查看数组的长度?
1、
[root@localhost ~]# echo ${#a[@]}     //前面加#数组的长度
6
[root@localhost ~]# echo ${#a[*]}    
6

数组分隔(切片):

${数组名[@]:offset:number}
offset #要跳过的元素个数
number #要取出的元素个数
#取偏移量之后的所有元素


[root@localhost ~]#echo ${a[*]}
a b c d e f
#数值a b c d e f
#位置0 1 2 3 4 5
[root@localhost ~]#echo ${a[*]:2:3}    #从2开始往后显示三个数(数组内数值位置是从0开始算的)
c d e
[root@localhost ~]#echo ${a[*]:0:5}    #从0开始显示五个数
a b c d e


[root@localhost ~]#num=({1..10})
[root@localhost ~]#echo ${num[*]}
1 2 3 4 5 6 7 8 9 10

#数值1 2 3 4 5 6 7 8 9 10
#位置0 1 2 3 4 5 6 7 8 9

[root@localhost ~]#echo ${num[*]:6}   #从位置6开始显示
7 8 9 10

数组替换:

[root@localhost ~]#echo ${a[*]}
a b c d e f

[root@localhost ~]#a[1]=9         #位置1的数替换为9
[root@localhost ~]#echo ${a[*]}
a 9 c d e f

改变数组显示:

[root@localhost ~]#echo ${a[*]/f/qwq}    #把f变为qwq显示出来。
a 9 c d e qwq
#只是改变了显示,并没有真正的修改

[root@localhost ~]#echo ${a[*]}
a 9 c d e f

列表与数组:

[root@localhost ~]#wu="1 2 3 4 5"
#先定义列表
[root@localhost ~]#wu1=($wu)
#再定义数组
[root@localhost ~]#echo ${wu1[@]}
1 2 3 4 5
1.8.2 冒泡排序

1、取出数组内的最大值与最小值

#!/bin/bash
read -p "请输入正整数字,并已空格隔开:" num
a=( $num )

max=${a[0]}
for ((i=0;i<${#a[*]};i++))
do
if [[ $max -lt ${a[$i+1]} ]]
then
max=${a[$i+1]}
fi
done
echo "最大值是$max"

min=${a[0]}
for ((i=0;i<${#a[*]}-1;i++))
do
if [[ $min -ge ${a[$i+1]} ]]
then
min=${a[$i+1]}
fi
done
echo "最小值是$min"

合并在一起并随机生成数字

#!/bin/bash
declare -i min max    #声明整数型变量
declare -a a          #声明数组变量
for ((i=0;i<10;i++))
do
  a[$i]=$[RANDOM%1000]
  [ $i -eq 0 ] && max=${a[0]} && min=${a[0]} &&continue
  [[ ${a[$i]} -gt $max ]] && max=${a[$i]} && continue
  [[ ${a[$i]} -lt $min ]] && min=${a[$i]}
done
echo ${a[*]}
echo max=$max
echo min=$min

2、对数组内的数字排序(排序算法,冒泡算法)

#!/bin/bash
a=(90 20 30 40 50)
#  0   1  2  3   4    下标
l=${#a[@]}
for ((i=1;i<$l;i++))
do
        for ((j=0;j<${l}-1;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[@]}

你可能感兴趣的:(linux,centos,运维)