函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,Shell 也支持函数。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
递归就是程序不断调用自身,递归方法就是方法直接或间接调用自身的方法。自己调用自己
1】反复执行的过程(调用自身)
2】结束反复执行过程的条件(方法跳出点)
写一个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
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
数组的特性就是一组数据类型相同的集合(不包括有一些编程语言提出来的关联数组的概念)。那么shell中数组是怎么定义的呢,我们来看两种数据类型:一是数值类型,二是字符串类型;虽然shell本身是弱类型的,但也可以这么区分。
获取数组的长度
获取元素的长度
遍历元素
元素切片
元素替换
元素删除
在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:
array_name=(数值1 数值2 数值3 ...... 数值n)
同样,使用一对括号表示数组,其中数组中的元素使用双引号或者单引号包含,同样使用“空格”来隔开:
arr_string=("abc" "edf" "sss"); 或者 arr_string=('abc' 'edf' 'sss');
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[*]},其中“*”表示的是所有,和@表示的一样含义
一般使用的是找出下标和数组长度之间的关系。
要求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
[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
通俗一点来说就是要交换两个瓶子中的水,必须找一个空瓶子作为媒介,根据一定的条件就可以换过来。
[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
定义一组数组
[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
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
echo $?,如果返回值是0则表示上一句没有错误,如果返回值是其他值表示有错误脚本。
[root@localhost opt]# sh arr1.sh |echo $?
2
arr1.sh:行5: 未预期的符号 `arr1[$i]=$[$i+1]' 附近有语法错误
arr1.sh:行5: `arr1[$i]=$[$i+1]'
选项:
-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]'