shell函数【递归函数】+shell数组【shell冒泡排列,求最大值】

shell函数+shell数组

一、shell函数

函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,Shell 也支持函数。Shell 函数必须先定义后使用。

【1】shell函数的格式

(1)定义一个函数

[function] fun_name () {
命令序列
[retrun n] ########返回的是状态码
[echo n] ######返回的是值
}
fun_name #########调用函数

Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。
如果 return 其他数据,比如一个字符串,往往会得到错误提示:“需要数字参数”。
调用函数只需要给出函数名,不需要加括号。如下所示:

[root@localhost opt]# vim hanshu1.sh
#!/bin/bash
function sum(){
  read -p "请输入加数:" num1
  read -p "请输入被加数:" num2
  sum=$(expr $num1 + $num2)
  [return abc]   #####中括号表示可有可无
  [echo $sum]
}
sum
#函数返回值在调用该函数后通过 $? 来获得
echo "返回值是:$?"
echo "和是:$sum"

[root@localhost opt]# sh hanshu1.sh 
请输入加数:45
请输入被加数:54
hanshu1.sh: 第 6 行:return: abc: 需要数字参数
返回值是:255  ####说明返回值是错的
和是:99
由于shell状态码最大是255,所以当返回值大于255时会出错

(2)全局声明函数
如果你希望直接从终端调用函数,可以将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用

[root@localhost ~]# vim .bashrc (局部声明)
[root@localhost ~]# source .bashrc (更新)
[root@localhost ~]# vim /etc/profile
pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}
[root@localhost ~]# source /etc/profile
【2】递归函数
(1)定义

递归就是程序不断调用自身,递归方法就是方法直接或间接调用自身的方法。自己调用自己

(2)特点

1】反复执行的过程(调用自身)
2】结束反复执行过程的条件(方法跳出点)

(3)举例说明

写一个shell脚本,列举出/var/log/下所有的文件,使用层次性输出。

查看/var/log的目录和文件
[root@localhost log]# tree /var/log
/var/log
├── anaconda
│   ├── anaconda.log
│   ├── ifcfg.log
│   ├── journal.log
│   ├── ks-script-2BcLC7.log
│   ├── packaging.log
│   ├── program.log
│   ├── storage.log
│   ├── syslog
│   └── X.log
├── audit
     └── audit.log

自定义递归函数,输出/var/log目录下的所有目录或文件

[root@localhost opt]# vim hanshu.sh
#!/bin/bash
#函数定义
function digui(){
#定义循环,in后面可以跟命令
  for f in `ls $1`
  do
  #判断是否是目录
    if [ -d "$1/$f" ];then
      echo "$2$f"
      digui "$1/$f" "  $2"
    else
      echo "$2$f"
    fi
  done
}
#调用函数
digui "/var/log" " "
[root@localhost opt]# sh hanshu.sh
 anaconda
   anaconda.log
   ifcfg.log
   journal.log
   ks-script-2BcLC7.log
   packaging.log
   program.log
   storage.log
   syslog
   X.log
 audit
   audit.log

二、shell数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
数组的特性就是一组数据类型相同的集合(不包括有一些编程语言提出来的关联数组的概念)。那么shell中数组是怎么定义的呢,我们来看两种数据类型:一是数值类型,二是字符串类型;虽然shell本身是弱类型的,但也可以这么区分。

【1】数组的作用

获取数组的长度
获取元素的长度
遍历元素
元素切片
元素替换
元素删除

【2】定义数组
(1)数值类数组的定义

在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:

    array_name=(数值1 数值2 数值3 ...... 数值n)
(2)字符串类型数组

同样,使用一对括号表示数组,其中数组中的元素使用双引号或者单引号包含,同样使用“空格”来隔开:

  arr_string=("abc" "edf" "sss"); 或者 arr_string=('abc' 'edf' 'sss');
(3)一般定义shell数组有四种写法:
1)定义一组:数组名=(数值1 数值2 数值3 ...... 数值n)
2)逐个定义:数组名=([0]=数值1 [1]=数值2 ...... [n-1]=数值n)
3)列表定义:列表名=“数值1 数值2 数值3 ...... 数值n”
           数组名=($列表名)
4)定义一个:数组名[0]=数值1
           数组名[1]=数值2
           数组名[2]=数值3
           数组名[n]=数值n+1

5)根据上面的定义,应该明白在数组中数值表示的是元素,0-n表示的是下标,输出数组是

echo ${arr[*]},其中“*”表示的是所有,和@表示的一样含义

一般使用的是找出下标和数组长度之间的关系。

(4)举例说明(快速创建数组、奇数数组)

要求1:快速创建一个数组,元素由用户自己定义

[root@localhost opt]# vim arr.sh 
#!/bin/bash
#快速创建一个数组
for ((i=0;i>=0;i++))
do
  read -p "请输入你需要定义数组元素:" num
##############如果用户输入的是空值则退出条件判断#################
  if [ -z $num ];then
  break
  else
###########定义数组,相当于列表定义################
    arr[$i]=$num
  fi
done
###############输出数组#####################
echo "你的数组是:${arr[*]}"
[root@localhost opt]# sh arr.sh
请输入你需要定义数组元素:12
请输入你需要定义数组元素:45
请输入你需要定义数组元素:56
请输入你需要定义数组元素:78
请输入你需要定义数组元素:56
请输入你需要定义数组元素:
你的数组是:12 45 56 78 56

要求2:列出1-100的数,并将1-100和1-100的奇数定义为数组

[root@localhost opt]# vim arr1.sh 
#!/bin/bash
#1-30
#由变量i控制1-30输出值,由变量j控制奇数输出
for ((i=0;i<=29;i++))
do
arr1[$i]=$[$i+1]
done
#1-30奇数
for ((j=0;j<30;j+=2))
do
arr2[$j]=$[$j+1]
done
echo "1-30的数组是:${arr1[*]}"
echo "1-30的奇数数组是:${arr2[*]}"
[root@localhost opt]# sh arr1.sh 
1-30的数组是:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
1-30的奇数数组是:1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
【3】shell数组的长度
(1)数组元素、下标、长度之间的关系

在这里插入图片描述

(2)数组长度的应用
1】求出一个数组中的最大值
[root@localhost opt]# vim arr2.sh
#!/bin/bash
#求数组最大值
score=(60 61 62 63 63 64 64 58 57 90)
temp=0
for ((i=0;i<${#score[*]};i++))
do
  if [ ${score[$i]} -gt $temp ];then
  temp=${score[$i]}
  fi
done
echo "score中的最大值是: $temp"
[root@localhost opt]# sh arr2.sh 
score中的最大值是: 90
【4】冒泡排序法
(1)示意图解

在这里插入图片描述
通俗一点来说就是要交换两个瓶子中的水,必须找一个空瓶子作为媒介,根据一定的条件就可以换过来。

(2)举例说明(升序排列)
[root@localhost opt]# vim arr3.sh 
#!/bin/bash
#快速创建一个数组
for ((i=0;i>=0;i++))
do
  read -p "请输入你需要定义数组元素:" num
#如果输入空字符,那么退出本次循环
  if [ -z $num ];then
  break
#否则把输入的数字赋值给数组元素
  else
    arr[$i]=$num
  fi
done
echo "你的数组是:${arr[*]}"

#定义数组前一个元素
for ((i=0;i<${#arr[*]};i++))
do
  #定义数组后一个元素
  for ((a=$i+1;a<${#arr[*]};a++))
  do
#条件判断,如果前一个元素大于后一个元素,就交换位置,否则下一次循环
  if [ ${arr[$i]} -gt ${arr[$a]} ];then
#交换位置
    temp=${arr[$i]}
    arr[$i]=${arr[$a]}
    arr[$a]=$temp
#
  fi
  done
done
echo "你的数组升序排列为:${arr[*]}"
[root@localhost opt]# sh arr3.sh 
请输入你需要定义数组元素:45
请输入你需要定义数组元素:1
请输入你需要定义数组元素:32
请输入你需要定义数组元素:55
请输入你需要定义数组元素:4
请输入你需要定义数组元素:
你的数组是:45 1 32 55 4
你的数组升序排列为:1 4 32 45 55
【5】数组的切片、替换、删除

定义一组数组

[root@localhost opt]# num=(45 54 65 23 12)
[root@localhost opt]# echo ${num[@]}
45 54 65 23 12

(1)数组的切片

格式:${数组名[*]:起始位置:长度}
[root@localhost opt]# echo ${num[*]:1:4}
54 65 23 12

(2)数组的替换

格式:数组名=${数组名[@]/查找的字符/替换的字符}
[root@localhost opt]# echo ${num[*]/23/32}
45 54 65 32 12

案例说明替换

[root@localhost opt]# vim arr5.sh
#!/bin/bash
#遍历数组,对未满60的数使用60替换
score=(12 90 80 99 43 60 90 4 5 7 8 4 3 4)
for ((i=0;i<${#score[*]};i++))
do
  if [ ${score[$i]} -le 60 ];then
    new[$i]=60
  else
    new[$i]=${score[$i]}
  fi
done
echo ${new[*]}
[root@localhost opt]# sh arr5.sh 
60 90 80 99 60 60 90 60 60 60 60 60 60 60

(3)数组的删除
内建命令 unset 用于销毁数组。unset name[subscript] 将销毁下标是 subscript 的元素。 unset name, 这里 name 是一个数组,或者 unset name[subscript], 这里
subscript 是 * 或者是 @,将销毁整个数组。
内建命令 declare, local, 和 readonly 都能接受 -a 选项,从而指定一个数组。内建命令 read 可以接受 -a 选项,从标准输入读入一列词来为数组赋值。
内建命令set 和 declare 使用一种可以重用为输入的格式来显示数组元素。

想具体了解请查看man手册,实在太多,就不列举了。
[root@localhost opt]# man unset | less
格式:unset 数组名
单个删除
[root@localhost opt]# unset num[2]
[root@localhost opt]# echo ${num[@]}
45 54 23 12
整个删除
[root@localhost opt]# unset num
[root@localhost opt]# echo ${num[@]}

[root@localhost opt]# 

案例说明删除

[root@localhost opt]# vim arr4.sh
#!/bin/bash
#遍历数组,对未满60的元素直接删除
score=(12 90 80 99 43 60 90 4 5 7 8 4 3 4)
i=0
for f in ${score[*]}
do
  if [ $f -lt 60 ];then
    unset score[$i]
  fi
  let i++
done
echo ${score[*]}
[root@localhost opt]# sh arr4.sh 
90 80 99 60 90
【6】调试命令
(1)set命令

set -x:开启调节模式
set +x:关闭调节模式
举例说明

[root@localhost opt]# vim arr4.sh 
#!/bin/bash
#遍历数组,对未满60的元素直接删除
score=(12 90 43 60 90 4 4)
i=0
for f in ${score[*]}
do
set -x
  if [ $f -lt 60 ];then
    unset score[$i]
  fi
set +x
  let i++
done
echo ${score[*]}
[root@localhost opt]# sh arr4.sh 
+ '[' 12 -lt 60 ']'
+ unset 'score[0]'
+ set +x
+ '[' 90 -lt 60 ']'
+ set +x
+ '[' 43 -lt 60 ']'
+ unset 'score[2]'
+ set +x
+ '[' 60 -lt 60 ']'
+ set +x
+ '[' 90 -lt 60 ']'
+ set +x
+ '[' 4 -lt 60 ']'
+ unset 'score[5]'
+ set +x
+ '[' 4 -lt 60 ']'
+ unset 'score[6]'
+ set +x
90 60 90
(2)echo

echo $?,如果返回值是0则表示上一句没有错误,如果返回值是其他值表示有错误脚本。

[root@localhost opt]# sh arr1.sh |echo $?
2
arr1.sh:行5: 未预期的符号 `arr1[$i]=$[$i+1]' 附近有语法错误
arr1.sh:行5: `arr1[$i]=$[$i+1]'
(3)bash/sh

选项:
-n:显示脚本错误
-v:显示脚本信息
-x:表示跟踪脚本

[root@localhost opt]# sh -n arr1.sh 
arr1.sh:行5: 未预期的符号 `arr1[$i]=$[$i+1]' 附近有语法错误
arr1.sh:行5: `arr1[$i]=$[$i+1]'
[root@localhost opt]# sh -v arr1.sh 
#!/bin/bash
#1-30
for ((i=0;i<=29;i++))
arr1[$i]=$[$i+1]
arr1.sh:行5: 未预期的符号 `arr1[$i]=$[$i+1]' 附近有语法错误
arr1.sh:行5: `arr1[$i]=$[$i+1]'
[root@localhost opt]# sh -x arr1.sh 
arr1.sh:行5: 未预期的符号 `arr1[$i]=$[$i+1]' 附近有语法错误
arr1.sh:行5: `arr1[$i]=$[$i+1]'
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值