目录
前言
学习函数,教我们如何将一段经常需要使用的代码封装起来,在需要使用时可以直接调用。
一、Shell函数
将命令序列按格式写在一起,可方便重复使用命令序列
1.1 Shell函数定义
[ function] 函数名(){
命令序列
[return x] #使用return或exit可以显式地结束函数
} #break:退出整个循环体
#continue:退出本次循环
1.2 调用函数的方法
函数名 [参数1] [参数2]
例1:两个数求和
[root@server2 ~]# vi sum.sh
#!/bin/bash
# 函数求和
sum(){ #函数名:sum; ():不带参数
read -p "第一个数:" num1
read -p "第二个数:" num2
echo "您输入这两个数为 $num1和$num2"
sum=$(($num1+$num2))
echo "这两个数的和为:$sum"
}
sum #调用函数
[root@server2 ~]# chmod +x sum.sh
[root@server2 ~]# ./sum.sh
第一个数:10
第二个数:23
您输入这两个数为 10和23
这两个数的和为:33
例2:
[root@server2 ~]# vim function
servicectl_usage(){
echo "Usage:service <service-name> <start|stop|restart|reload|status>"
return 1
}
chk_centos_ver(){
grap "CentOS.*release 7." /etc/centos-release &> /dev/null && echo "7"
grap "CentOS.*release 6." /etc/centos-release &> /dev/null && echo "6"
grap "CentOS.*release 5." /etc/centos-release &> /dev/null && echo "5"
}
servicectl(){
[[ -z $1 || -z $2 ]] && servicectl_usage
[ $(chk_centos_ver)=="7" ] && systemctl $2 $1 || service $1 $2
}
[root@server2 ~]# chmod +x function
[root@server2 ~]# source function #成为环境变量
[root@server2 ~]# echo 'source /root/function' >> ~/.bashrc
1.3 函数的作用范围
函数在Shell脚本中仅在当前Shell环境中有效
Shell脚本中变量默认全局有效
将变量限定在函数内部使用local命令
例:
[root@client2 ~]# vi fun_scope. sh
myfun( ){ #定义一个函数myfun
local i #局部变量
i=8 #局部变量赋值
echo $i
}
i=9
myfun #变量调用,8
echo $i #i为9
[ root@client2 ~]#chmod +x fun_scope.sh
[root@client2 ~]# ./fun_scope. sh
8
9
修改验证:
[root@client2 ~]# vi fun_scope. sh
myfun( ){ #定义一个函数myfun
i=10 #全局变量赋值
echo $i
}
i=9
myfun #全局变量调用,i=9也会被覆盖为10
echo $i #i为10
[ root@client2 ~]#chmod +x fun_scope.sh
[root@client2 ~]# ./fun_scope. sh
10
10
二、函数的参数
2.1 参数的用法
函数名称 参数1 参数2 参数3 …
2.2 参数的表示方法
$1 $2 $3 … ${10} ${11} …
例:
[ root@client2 ~]# vi write_log. sh
#!/ bin/ bash
# 文件内容写入
mydir=/data
outfile=${mydir}/my . log
[ -e "${mydir}" ] ll mkdir ${mydir} #目录或文件是否存在,或者创建一个
appendfile (){ #定义一个函数
echo "$2" >> $1 #"$2"追加到$1,$1空的
}
appendfile ${outfile} "first line content." #first line content.追加到${outfile}内
appendfile ${outfile} "second line content." #second line content.追加到${outfile}内
[ root@client2 ~]# chmod +x write_log.sh
[ root@client2 ~]# ./write_log.sh
[root@client2 ~]# cat /data/my . log #查看
first line content.
second line content.
三、递归函数
调用自己本身的函数
例:
[root@client2 ~]# vi fun_recursion. sh
list_files ( ){
for f in `ls $1` #$1为下面解释/var/log
do
if [ -d "$1/$f” ] #查看/var/log下$f是否为目录
then echo "$2$f" #显示$f,$2下面解释是空
list_files "$1/$f" " $2"
#再次调用函数,$1为"$1/$f",$2为" $2",带入前面循环,查看"$1/$f/$f"是否为目录,是则显示" $2",一直循环
else #别的,查看不是目录的
echo "$2$f" #显示"$f"
fi
done
}
list_files " /var/log" ""
[ root@client2 ~]# cd /var/log/
[root@client2 log]# mkdir -p a/b/c #递归创建目录
[root@client2 log]# cd a/b/c/
[root@client2 c]# vi 1.txtl #c目录里创建文件
111111111111111111111
[root@client2 c]# cd #切换到宿主目录
[ root@client2 ~]# chmod +x ./fun_recursion. sh
[ root@client2 ~]# ./fun_recursion. sh
四、Shell数组
应用场景包括:
获取数组长度
获取元素长度
遍历元素
元素切片
元素替换
元素删除
…
4.1数组定义方法
例:
方法一:数组名=(value0 value1 value2 ...)
方法二:数组名=([0]=value [1]=value [2]=value ...) #[0] [1]...这些为下标,代表位置
方法三:列表名="value0 value1 value2 ..."
数组名=($列表名)
方法四:数组名[0]="value"
数组名[1]="value"
数组名[2]=”value"
4.2数组包括的数据类型
数值类型
字符类型
使用""或"定义
4.3 Shell数组操作
1.获取数组数值
${数组名[@/*]} #@或*
例:
[root@server2 ~]# a=(1 2 3 4 5)
[root@server2 ~]# echo ${a[*]}
1 2 3 4 5
2.获取数组长度
${#数组名[@/*]}
例:
[root@server2 ~]# a=(1 2 3 4 5)
[root@server2 ~]# echo ${#a[*]}
5
3.读取某下标赋值
${数组名[下标]} #下标排序是从0号位开始排序的
例:
[root@server2 ~]# a=(1 2 3 4 5)
[root@server2 ~]# echo ${a[0]} #显示0号位
1
4.数组遍历
例:
[root@client2 ~]# vi num1.sh
#!/bin/bash
# 数组循环
a=(1 2 3 4 5)
for num in ${a[*]} #$num是数组里的一个值
do
echo $num
done
[root@client2 ~]# chmod +x num1.sh
[root@client2 ~]# ./num1.sh
1
2
3
4
5
5.数组切片
${数组名[@/*]:起始位置:长度}
例:
[root@client2 ~]# vi num1.sh
#!/bin/bash
# 数组循环
a=(1 2 3 4 5)
for num in ${a[*]:1:2} #$num是数组里0号位为起始位置,长度2的数
do
echo $num
done
[root@client2 ~]# chmod +x num1.sh
[root@client2 ~]# ./num1.sh
2
3
6.数组的替换 #数值没有真正被替换,只是输出显示
${数组名[@/*]/查找字符/替换字符}
例:
[root@client2 ~]# a=(1 2 3 4 5)
[root@client2 ~]# echo ${a[@]/2/22} #查找下标2替换为22
1 22 3 4 5
[root@client2 ~]# echo ${a[*]} #数值没有被真正替换
1 2 3 4 5
[root@client2 ~]# a1=${a[*]/2/22}
[root@client2 ~]# echo $al
1 22 3 4 5
7.数组删除
unset
例:
[root@client2 ~]# a=(1 2 3 4 5)
[root@client2 ~]# echo ${a[@]}
1 2 3 4 5
[root@client2 ~]# unset a
[ root@client2 ~]# echo ${a[@]}
#空的,已删除
五、Shell脚本调试
echo命令
bash命令
命令语法:sh [-nvx] 脚本名
常用选项-n、-v、-x
-n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任何内容,如果有问题会提示报错。
-v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示。
-x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数。
set命令
set-x:开启调节模式
set+x:关闭调节模式
例:
[root@client2 ~]# vi grade.sh
#!/bin/bash
set -x //开启调试模式
read -p "请输入您的分数(0-100):" GRADE
if [ $GRADE -ge 85 ]&&[ $GRADE -le 100 ]
then
echo "$GRADE 分!优秀" set +x //关闭调试模式
elif [ $GRADE -ge 70 ] && [$GRADE -le 84 ]
then
echo "$GRADE 分,合格" else
echo "$GRADE 分?不合格"
fi
[root@client2 ~]# sh -n grade. sh #不会执行该脚本,语法没错误
[root@client2 ~]# sh -v grade. sh #执行脚本输出到屏幕
# ! /bin/ bash
set -x //开启调试模式
read -p "请输入您的分数(0-100):" GRADE
+ read -p '请输入您的分数(0-100):' GRADE
请输入您的分数(0- 100 ):85
if [ $GRADE -ge 85 ]&&[ $GRADE -le 100 ]
then
echo "$GRADE 分!优秀" set +x //关闭调试模式
elif [ $GRADE -ge 70 ]&&[ $GRADE -le 84 ]
then
echo "$GRADE 分,合格" else
echo "$GRADE 分?不合格"
fi
+ '[’ 85 -ge 85 ']'
+ '[’ 85 -le 100 ']'
+ echo '85分!优秀' set +x $ '//\345\205\263\351\227\255\350\22031350\257\2251346\2501241\3451274\217'
85 分!优秀set +x //关闭调试模式
[root@client2 ~]# sh grade.sh
+ read -p '请输入您的分数(0-100): ' GRADE
请输入您的分数(0-100): 70
+ '[’ 70 -ge 85 ']'
+ '[’ 70 -ge 70 ']'
+ '[' 70 -le 84 ']'
+ echo '70分,合格' else
70分,合格 else
+echo '70分?不合格'
70 分?不合格
六、冒泡排序
注:数值的长度-排序的轮数=比对的次数
解析:通过对数据循环排序,得出数值大小,进行排序
排序流程
score =(10 5 1 100 70 60)
第一轮 比较了5次
10 5 1 100 70 60
5 10 1 100 70 60 1次 #5和10比
5 1 10 100 70 60 2次 #10和1比
5 1 10 100 70 60 3次 #10和100比
5 1 10 70 100 60 4次 #100和70比
5 1 10 70 60 100 5次 #100和60比 得出最大数值
第二轮 比较了4次
5 1 10 70 60
1 5 10 70 60 1次
1 5 10 70 60 2次
1 5 10 70 60 3次
1 5 10 60 70 4次 得出倒数第二大数值
第三轮 比较了3次
1 5 10 60 得出倒数第三大数值
第四轮 比较了2次
1 5 10 得出倒数第四大数值
第五轮 比较了1次
1 5 得出倒数第五大数值
例1:
[root@client2 ~]# vi maopao1.sh
#!/ bin/ bash
# 冒泡排序
score=(70 10 40 100 5 60)
for ((i=1;i<${#score[*]};i++)) #排序轮数
do
for ((j=0 ; j<${#score[*]}-$i; j++)) #因为比对次数从0开始,所以<数值的长度-排序的轮数
do
if [ ${score[ j ]} -gt ${score[ j+1 ]} ] #当前面的数大于后面的数的时候
then temp=${score[ j ]} #添加temp数值为前面大的数值
score[ j ]=${score[ j+1 ]} #把后面大的数值替换前面小的数值
score[ j+1 ]=$temp #后面大的数值=原来前面小的数值
fi
done
done
echo ${score[*} #显示输出score全部数值
[root@client2 ~]# chmod +x maopao1.sh
[root@client2 ~]# ./maopao1.sh
5 10 40 60 70 100
例2: 键盘输入冒泡排序
[root@client2 ~]# vi maopao1.sh
#!/ bin/ bash
# 键盘输入冒泡排序
k=0 #数组元素第0个
while true #条件为真时一直循环
do
read -p"是否需要输入数值? " do
if [ $do == "no"] #当输入no时
then break #退出整个循环
fi
read -p "请输入第$(($k+1))个元素" key
score[$k]=$key
let k++
done
for ((i=1;i<${#score[*]};i++)) #排序轮数
do
for ((j=0 ; j<${#score[*]}-$i; j++)) #因为比对次数从0开始,所以<数值的长度-排序的轮数
do
if [ ${score[ j ]} -gt ${score[ j+1 ]} ] #当前面的数大于后面的数的时候
then temp=${score[ j ]} #添加temp数值为前面大的数值
score[ j ]=${score[ j+1 ]} #把后面大的数值替换前面小的数值
score[ j+1 ]=$temp #后面大的数值=原来前面小的数值
fi
done
done
echo ${score[*} #显示输出score全部数值
[root@client2 ~]# chmod +x maopao1.sh
[root@client2 ~]# ./maopao1.sh
是否需要输入数值? y #只要不输入no就继续
请输入第1个元素5
是否需要输入数值? y
请输入第2个元素22
是否需要输入数值? y
请输入第3个元素15
是否需要输入数值? y
请输入第4个元素3
是否需要输入数值? y
请输入第5个元素120
是否需要输入数值? y
请输入第6个元素50
是否需要输入数值? no
3 5 15 22 50 120