Linux之函数与数组

函数与数组

函数

Shell 函数

  1. 将命令序列按格式写在一起
  2. 可方便重复使用命令序列
  3. 使用函数可以避免代码重复
  4. 使用函数可以将大的工程分割为若干小的功能模块,代码的可读性更强

Shell 函数定义

方式一:
function 函数名 {
    命令序列
}
方式二:
函数名 () {
      命令序列
}
函数返回值
  • return表示退出函数并返回一个退出值,脚本中可以用 $? 变量显示该值
使用原则
  • 函数一结束就取回返回值,因为 $? 变量只返回执行的最后一条命令的退出状态码
  • 退出状态码必须是0-255,超出时值将为除以256取余 exit 0
举例:
方式一:

[root@gcc jiaoben1]#vim test3.sh
#!/bin/bash
function abc {                           #使用function进行函数定义
   read -p "请输入:" a
   a=$[$a*2]
   return $a                             #return表示退出函数并返回一个退出值,脚本中可以用 $? 变量显示该值,我们执行的返回码用于判断命令是否执行成功
}
abc
echo $?                                  #退出状态码必须是0-255,超出时值将为除以256取余

function abc {
   read -p "请输入:" a
   a=$((a*2))
   return 0
}

# 调用函数并将其返回值保存在result变量中
abc
result=$?

# 检查返回值是否为0,并打印result变量的值
if [ $result -eq 0 ]
then
   echo "函数返回值为:$a"
else
   echo "函数执行出错!"
fi
补充:

return和exit的区别在于它们的作用范围:return只作用于函数内部,而exit作用于整个脚本。
如果想从函数中返回一个值并继续执行脚本,应该使用return语句;
如果想在任何时候结束整个脚本的执行,应该使用exit语句。

在这个例子中,abc 函数会提示用户输入一个数,并将输入的数乘以 2 作为返回值。
当 abc 函数执行完毕后,使用 echo $? 命令输出函数的退出状态码。
由于 abc 函数返回的是一个数值,因此它的退出状态码也是一个数值。
在这个例子中,假设用户输入的是 3,
那么 abc 函数将会返回 6。因此,当执行 echo $? 命令时,输出的结果将会是 6。
需要注意的是,函数的返回值只能是一个整数值,
而且在 Shell 中,退出状态码必须在 0 到 255 之间。
如果计算结果超出了这个范围,需要对结果进行取余操作,以确保它是一个合法的退出状态码。

在 Shell 脚本中,return 语句用于指定函数的退出状态码(返回码)。约定俗成地,
返回码为 0 表示成功,非零值表示失败或错误。

返回码的具体含义是由你自己定义的,只要符合约定即可。你可以根据自己的需要定义不同的返回码和其对应的含义。

Shell中的 return 命令通常用于在函数内部控制流程,并将状态码或结果传递给调用者。
它的主要作用是告诉调用者函数的执行状态或结果,并不像其他语言中的 return 语句那样直接返回函数结果。

Shell中的 return 命令主要用于控制函数的退出状态码或返回结果,以便在函数调用后进行相应的处理。
虽然Shell中的 return 不同于其他语言中的返回语句,但在Shell脚本编程中,它仍然具有一定的作用和用途。

在编写 Shell 脚本时,根据函数的执行结果来设置适当的返回码是一种良好的编程习惯,
它可以帮助调用者根据返回码来判断函数的执行状态,并根据需要采取相应的措施

在 Shell 函数中,可以使用 exit 语句来终止函数的执行并返回一个退出状态码。
当函数执行到 exit 语句时,整个脚本将立即停止执行,并将指定的退出状态码返回给调用者

方法二:
[root@gcc jiaoben1]#vim test4.sh

#!/bin/bash
abc () {                              
    read -p "请输入:" a
    a=$[$a*2]
    echo $a
}
abc                                            #直接使用函数名进行运算,这里加了abc就会输出两次
或者
result=$(abc)
echo $result
----------------------------------------------------------------
[root@gcc jiaoben1]#./test4.sh 
请输入:400
800

函数传参

  • 在Shell中,调用函数时可以向其传递参数。
  • 在函数体内部,通过 $n 的形式来获取参数的值,
  • 例如,$1表示第一个参数,$2表示第二个参数…即使用位置参数来实现参数传递。
方式一:
[root@gcc jiaoben1]#vim test5.sh
#!/bin/bash
sum1 () {
   sum=$[$1 + $2]
   echo $sum
}

read -p "请输入第一个参数:" first
read -p "请输入第二个参数:" second
sum1 $first $second:
----------------------------------------------------------------------------
[root@gcc jiaoben1]#chmod +x test5.sh 
[root@gcc jiaoben1]#./test5.sh 
请输入第一个参数:2
请输入第二个参数:3
5
方式二:
[root@gcc jiaoben1]#vim test5.sh
#!/bin/bash
sum1 () {
   sum=$[$1 + $2]
   echo $sum
}

sum1 $1 $2
---------------------------------------------------------------------------
[root@gcc jiaoben1]#./test5.sh  10 20
30

函数变量的作用范围

  • 函数在shell脚本中仅在当前shell环境中有效
  • shell脚本中的变量默认全局有效
  • 将变量限定在函数内部使用local命令
示例
[root@gcc jiaoben1]#vim test5.sh
#!/bin/bash
abc () {
   a=5
   b=6
   return $a $b   #在函数内部定义了全局变量,外部的赋值不能改变全局变量
}

a=8
b=12
c=9
abc
echo "a等于$a"
echo "b等于$b"
echo "c等于$c"

#!/bin/bash
abc () {
   local a=5     #用了local就是函数内部的变量,外部重新赋值会替换这个变量
   local b=6
   return $a $b
}

a=8
b=12
c=9
abc
echo "a等于$a"
echo "b等于$b"
echo "c等于$c"

[root@gcc jiaoben1]#vim test5.sh
#!/bin/bash
abc () {
   local i=8
   echo "inside $i"
}

i=9
abc
echo "outside $i"
------------------------------------------------------------------------
[root@gcc jiaoben1]#./test5.sh
inside 8
outside 9

[root@gcc jiaoben1]#vim test5.sh
#!/bin/bash
abc () {
   echo "inside1 $i"
   let i++
   local i
   i=8
   echo "inside2: $i"
}

i=9
abc
echo "outside $i"
----------------------------------------------------------------
[root@gcc jiaoben1]#./test5.sh
inside1 9
inside2: 8
outside 10

函数递归

  • 函数调用自己本身的函数
阶乘

阶乘,也是数学里的一种术语。阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。 6 12345*6 8 12345678例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。 例如所要求的数是6,
则阶乘式是1×2×3×……×6,得到的积是720,720就是6的阶乘。例如所要求的数是n,则阶乘式是1×2×3×……×n,设得到的积是x,x就是n的阶乘。

在表达阶乘时,就使用“!”来表示。如h阶乘,就表示为h!

[root@gcc jiaoben1]#vim test6.sh
#!/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 "请输入阶乘数:" n
result=`fact $n`
echo "$result"
阶乘解释

调用fact函数,并将5作为输入参数传递进去。
在fact函数内部,判断输入参数是否等于1。由于输入参数为5,所以不等于1。
将输入参数减1,得到4。然后递归调用fact函数,并将4作为输入参数传递进去。
在新的fact函数内部,同样判断输入参数是否等于1。由于输入参数为4,所以不等于1。
将输入参数减1,得到3。然后递归调用fact函数,并将3作为输入参数传递进去。
在新的fact函数内部,同样判断输入参数是否等于1。由于输入参数为3,所以不等于1。
将输入参数减1,得到2。然后递归调用fact函数,并将2作为输入参数传递进去。
在新的fact函数内部,同样判断输入参数是否等于1。由于输入参数为2,所以不等于1。
将输入参数减1,得到1。然后递归调用fact函数,并将1作为输入参数传递进去。
在新的fact函数内部,判断输入参数是否等于1。由于输入参数为1,所以等于1。
直接返回1。
回到第9步的fact函数中,将输入参数1乘以结果1,得到1。
回到第7步的fact函数中,将输入参数3乘以结果1,得到3。
回到第5步的fact函数中,将输入参数4乘以结果3,得到12。
回到第3步的fact函数中,将输入参数5乘以结果12,得到60。
将60作为返回值返回给主程序,存储在result变量中。
打印result变量的值,即60。

递归目录
[root@gcc jiaoben1]#vim test7.sh
#!/bin/bash
function list_files {
    for f in `ls $1`
    do
      if [ -d "$1/$f" ]
      then
          echo "$f"                  #如果是目录就输出这个目录,$2为空格是用于区分父子目录
          list_files "$1/$f"
      else
          echo "$f"                   #不是目录则输出$f结果
      fi
     done
}
list_files $1

[ -d "$1/$f" ]中,斜杠(/)用于将参数$1和变量$f连接起来,以构造一个路径,用于检查是否存在一个指定的目录。
例如,如果参数$1包含/home/user,变量$f包含mydir,则路径/home/user/mydir将被构造出来,
并用于检查是否存在一个名为mydir的目录。
函数库
  • 函数库只包含函数的定义,脚本中既包含函数的定义也包括可执行的代码。
[root@gcc jiaoben1]#vim test8.sh
#!/bin/bash
jiafa () {
  result=$[$1 + $2]
  echo $result
}

jianfa () {
   result=$[$1 - $2]
   echo $result
}

chengfa () {
   result=$[$1 * $2]
   echo $result
}
chufa () {
    if [ $2 -ne 0 ]
    then
        result=$[$1 / $2]
        echo $result
    else
      echo "$2不能等于0!"
    fi
}

----------------------------------------------------------------------------
[root@gcc jiaoben1]#vim test9.sh
#!/bin/bash
. /opt/jiaoben1/test8.sh
read -p "输入第一个参数值:" first
read -p "输入第二个参数值:" second

result1=`jiafa $first $second`
result2=`jianfa $first $second`
result3=$(chengfa $first $second)
result4=$(chufa $first $second)

echo $result1
echo $result2
echo $result3
echo $result4
--------------------------------------------------------
[root@gcc jiaoben1]#chmod +x test9.sh 
[root@gcc jiaoben1]#./test9.sh  
输入第一个参数值:20
输入第二个参数值:10
30
10
200
2

数组

数组定义方法

方法一:
数组名=(value0 valuel value2 …)

举例:
[root@loaclhost shuzu1]#arr=(1 2 3 4 5)

[root@loaclhost shuzu1]#echo ${arr[*]}
1 2 3 4 5
方法二:
数组名=( [0]=value [1]=value [2]=value …)

举例:
[root@loaclhost shuzu1]#arr=([0]=1 [1]=2 [2]=3)

[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3
方法三:
列表名=“value0 valuel value2 …”
数组名=($列表名)

举例:
[root@loaclhost shuzu1]#list="1 2 3 4"
[root@loaclhost shuzu1]#arr2=($list)

[root@loaclhost shuzu1]#echo ${arr2[*]}
1 2 3 4
方法四:
数组名[0]=“value”
数组名[1]=“value”
数组名[2]=“value”

举例:
root@loaclhost shuzu1]#arr3[0]="1"
[root@loaclhost shuzu1]#arr3[1]="2"
[root@loaclhost shuzu1]#arr3[2]="3"

[root@loaclhost shuzu1]#echo ${arr3[*]}
1 2 3

数组包括的数据类型

  • 数值类型
  • 字符类型
  • 使用" "或‘ ’定义

获取数组长度

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${#arr1[*]}      #也就是数组中总共多少个元素
5

读取某下标赋值

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)

[root@loaclhost shuzu1]#echo ${arr1[0]}      #获取索引为0的元素,即第一个元素
1
[root@loaclhost shuzu1]#echo ${arr1[3]}      #获取索引为3的元素,即第四个元素
4

数组遍历

[root@loaclhost shuzu1]#vim a.sh
#!/bin/bash
arr5=(1 2 3 4 5)
for i in ${arr5[*]}   或  for i in ${arr5[@]}     #使用*或者@表示都可以
do
  echo $i
done

[root@loaclhost shuzu1]#chmod +x a.sh 
[root@loaclhost shuzu1]#./a.sh           #将数组中的元素列出来就叫数组遍历
1
2
3
4
5

数组切片

取数组中的某一段的元素的值

格式:
${数组名[@或*]}:起始位置(起始索引):长度

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]}         #输出整个数组
1 2 3 4 5
[root@loaclhost shuzu1]#
[root@loaclhost shuzu1]#echo ${arr1[*]:0:2}      #这里是从0索引开始获得往后两位元素的值
1 2
[root@loaclhost shuzu1]#echo ${arr1[*]:2:2}      #获取从索引2开始往后的两位元素的值
3 4

数组替换

临时替换或者永久替换

格式:
$(数组名[@或*]/查找字符/替换字符}

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]/4/66}     #将数组arr1中的元素4替换为66,这只是临时替换,并不是永久替换
1 2 3 66 5
[root@loaclhost shuzu1]#echo ${arr1[*]}          #原来的数组中的元素的值并不会改变
1 2 3 4 5 

[root@loaclhost shuzu1]#arr1=(${arr1[*]/4/66})    #如果想要永久替换的话,可通过重新赋值实现
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 66 5

[root@test1 opt]# arr1[3]=44
[root@test1 opt]# echo ${arr1[*]}
1 2 3 44 5 6

删除数组

使用unset删除数组

[root@loaclhost shuzu1]#unset arr1
[root@loaclhost shuzu1]#echo ${arr1[*]}

删除数组中的某个索引对应的元素的值

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5
[root@loaclhost shuzu1]#unset arr1[2]       #删除索引2的对应的元素值
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 4 5

追加数组中的元素

当想要在数组中原有的元素后面再追加一些元素的话,可以使用如下方法实现追加:

方法一:

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5                            #这是原始的数组中的各元素的值,一直到索引4结束
--------------------------------------------------------------------------------
[root@loaclhost shuzu1]#arr1[5]=6          #此时追加数组索引5对应的元素值为6
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5 6                          #发现数组的索引5位置上的元素已经追加成功

方法二:

[root@loaclhost shuzu1]#arr1[${#arr1[*]}]=7      
#当数组的元素非常多的时候,可以直接使用数组的长度作为自己将要追加的索引的值,这样就可以直接追加元素了。
因为原始数组的索引是从0开始的,所以用长度减去1就是原始数组的最后的以为索引值了,
那么自己将要添加的值应该是原始索引值的后一位,那显然就等于数组的长度值了。
[root@loaclhost shuzu1]#echo ${arr1[*]} 
1 2 3 4 5 6 7

方法三:

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5
---------------------------------------------------------
[root@loaclhost shuzu1]#arr1=("${arr1[@]}" 6 7)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5 6 7

双引号不能省略,否则,当数组arr1中存在包含空格的元素时会按空格将元素拆分成多个。
不能将“@“替换为“*”,如果替换为"*",
不加双引号时与"@"的表现一致,加双引号时,会将数组arr1中的所有元素作为一个元素添加到数组中。
可以简单的理解为:用*号是作为一个整体,而用@还是单个的个体。

$*、$@不加双引号时表现一致;加双引号时,$*会将所有参数作为一个整体。

[root@loaclhost shuzu1]#abc=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${abc[*]}
1 2 3 4 5
[root@loaclhost shuzu1]#abc=(${abc[@]} 6 7 8) #用@可以不加引号
[root@loaclhost shuzu1]#echo ${abc[*]}
1 2 3 4 5 6 7 8
[root@loaclhost shuzu1]#for i in ${abc[*]}
> do
> echo $i
> done
1
2
3
4
5
6
7
8
--------------------------------------------------------------------------------
[root@loaclhost shuzu1]#abc1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${abc1[*]}
1 2 3 4 5
[root@loaclhost shuzu1]#abc1=("${abc1[*]}" 6 7 8)
[root@loaclhost shuzu1]#echo ${abc1[*]}
1 2 3 4 5 6 7 8
[root@loaclhost shuzu1]#for i in "${abc1[@]}";do echo $i;done
1 2 3 4 5

方法四:

[root@loaclhost shuzu1]#arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5
-----------------------------------------------
[root@loaclhost shuzu1]#arr1+=(11 22)
[root@loaclhost shuzu1]#echo ${arr1[*]}
1 2 3 4 5 11 22


待添加元素必须用“()"包围起来,并且多个元素用空格分隔

向函数传数组参数

1、如果将数组变量作为函数参数,函数只会取数组变量的第一个值。如下:

[root@loaclhost shuzu1]#vim b.sh 
#!/bin/bash
test1 () {
   echo "接受到的参数列表:$@"
   abc2=$1                 
   echo "新数组的值为:${abc2[*]}" 
}

abc=(3 2 1 4 5)
echo "原始数组的值为:${abc[*]}"
test1 $abc                          #将数组变量作为函数的参数,只会取数组变量的第一个值
------------------------------------------------------------------------------------
[root@loaclhost shuzu1]#chmod +x b.sh 
[root@loaclhost shuzu1]#./b.sh 
原始数组的值为:3 2 1 4 5
接受到的参数列表:3
新数组的值为:3


2、解决这个问题则需要将数组变量的值分解成单个的值,
然后将这些值作为函数参数使用。在函数内部,再将所有的参数重新组合成一个新的数组变量。如下:

$*、$@不加双引号时表现一致;加双引号时,$*会将所有参数作为一个整体。
[root@loaclhost shuzu1]#vim c.sh
#!/bin/bash
test2 () {
  abc1=($(echo $@))                       或者表示为   abc1=(`echo $@`)

  echo "新数组的值为:${abc1[*]}"
}

abc=(`seq 1 10`)
test2 ${abc[*]}                           #将数组的值分解为单个的值
-------------------------------------------------
[root@loaclhost shuzu1]#chmod +x c.sh 
[root@loaclhost shuzu1]#./c.sh 
新数组的值为:1 2 3 4 5 6 7 8 9 10


3、从函数返回数组(调用新数组的元素进行函数运算)
举例1:(加法传参运算)

[root@loaclhost shuzu1]#vim c.sh
#!/bin/bash
test2 () {
  abc1=(`echo $@`)
  sum=0
  for i in ${abc1[*]}
  do
    sum=$[$sum + $i]
  done
  echo "$sum"
}

abc=(3 2 1 4 5)
test2 ${abc[*]}
--------------------------------------------------------------
[root@loaclhost shuzu1]#chmod +x c.sh 
[root@loaclhost shuzu1]#./c.sh 
15


举例2:(乘法传参运算)

[root@loaclhost shuzu1]#vim c.sh
#!/bin/bash
test3 () {
  abc1=(`echo $@`)
  for ((i=0;i<=$[$# - 1];i++))           #$#是原始数组的元素个数,这里是取出新数组的索引值,不减的话就是一个字符串
  do
    abc1[$i]=$[${abc1[$i]} * 2]          #这里是将每个原始索引对应的元素值乘以2传到新的数组中对应的索引的元素中去
  done
  echo "${abc1[*]}"                      #输出新的数组
}

abc=(1 2 3)
test3 ${abc[*]}
-----------------------------------------------------------------------
[root@loaclhost shuzu1]#./c.sh 
2 4 6

数组排序算法:冒泡排序

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

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

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

在实际应用中,冒泡排序适用于对小规模数据进行排序


#!/bin/bash
abc=(20 10 60 40 50 30)          #定义一个数组
echo "原数组的排列顺序为:${abc[*]}"
length=${#abc[*]}                #定义原数组的长度为length变量
for ((i=1;i<$length;i++))        #定义排序轮次
do
    echo $i
  for ((k=0;k<$length-i;k++))    #确定第一个元素的索引位置
  do
     first=${abc[$k]}            #定义第一个元素的值
     j=$[$k+1]                   #定义第二个元素的索引号
     second=${abc[$j]}           #定义第二个元素的值
     if [ $first -gt $second ]   #第一个元素和第二个元素比较,如果第一个元素比第二个元素大则互换
     then             
         temp=$first             #把第一个元素的值保存在临时变量temp中
         abc[$k]=$second         #把第二个元素的值赋给第一个元素
         abc[$j]=$temp           #把原第一个元素的值,赋给第二个元素
     fi
  done
done

echo "排序后数组的排列顺序为${abc[*]}"       #输出排序后的数组
---------------------------------------------------------------------------------------
[root@loaclhost shuzu1]#./g.sh 
原数组的排列顺序为:20 10 60 40 50 30
排序后数组的排列顺序为10 20 30 40 50 60
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值