-=======================================================================
张贺,多年互联网行业工作经验,担任过网络工程师、系统集成工程师、LINUX系统运维工程师笔者微信:zhanghe15069028807,现居济南历下区
-=======================================================================
函数
函数基础
什么是函数?
函数其实就是一堆命令的合集,用来完成特定功能的代码块,你可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数,要使用定义的函数,只需要填写函数名就可以了。
函数的作用?
使用函数可以让代码模块化,便于代码的复用,同时增加脚本的可读性。
函数和变量类似,必须先定义才可调用,如果定义不调用则不会被执行。
如何调用shell函数,直接使用函数名调用即可,在函数内部也可以使用$1,$2,$3的方式传递参数。
[root@test2 ~]# fun1() { echo "hello,shell"; }
[root@test2 ~]# fun1
//给函数传递参数
[root@test2 ~]# fun2() { echo "hello,$1"; }
[root@test2 ~]# fun2 linux
hello,linux
//给函数传递多个参数
[root@test2 ~]# fun3() { echo "hello $*"; }
[root@test2 ~]# fun3 zhangsan lisi wangwu
hello zhangsan lisi wangwu
[root@test2 tmp]# cat 1.sh
#!/bin/bash
function fun1 {
#这里面的$1位置参数,并不会生效
echo "这是第一个函数 $1"
}
fun2(){
echo "这是第二个函数"
}
fun1
[root@test2 tmp]# /bin/bash 1.sh test
这是第一个函数
[root@test2 tmp]# cat 1.sh
#!/bin/bash
function fun1 {
echo "这是第一个函数 $1"
}
fun2(){
echo "这是第二个函数"
}
fun1 $1 #test1赋值到这个$1,然后通过函数又赋值到上面的$1了。
[root@test2 tmp]# /bin/bash 1.sh test
这是第一个函数 test
函数参数传递
注意:位置参数和函数里面的位置参数没有关系,而和函数之外的位置参数有关系。
如何向函数传递参数,其实函数的传参和脚本的传参类似,都是使用$1,$2,$3,$4方式。
- 函数传参示例,使用变量的方式传递固定值。
[root@test2 tmp]# cat 2.sh
fun_1(){
echo "$sum"
}
sum=10
fun_1
[root@test2 tmp]# /bin/bash 2.sh
10
- 函数传参示例,使用变量方式传递可变的值
[root@test2 tmp]# cat 2.sh
fun_1(){
echo "$sum"
}
sum=$1
fun_1
[root@test2 tmp]# /bin/bash 2.sh test
test
[root@test2 tmp]# cat 3.sh
fun_1 () {
echo "$1"
}
fun_1 $1
fun_1 $2
fun_1 $3
[root@test2 tmp]# /bin/bash 3.sh test1 test2 test3
test1
test2
test3
[root@test2 tmp]# cat 3.sh
fun_1 () {
echo "$1" "$2" "$3"
}
rc=$(fun_1 $1 $2 $3)
echo "你传递的变量是 $rc"
[root@test2 tmp]# /bin/bash 3.sh test1 test2 test3
你传递的变量是 test1 test2 test3
[root@test2 tmp]# cat 3.sh
fun_1 () {
echo "$1" "$2" "$3"
}
fun_1 $2 $1 $3
[root@test2 tmp]# /bin/bash 3.sh test1 test2 test3
test2 test1 test3
[root@test2 ~]# cat 1.sh
#!/bin/bash
cale () {
case $2 in
+)
echo $1 + $3 = $(( $1 + $3))
;;
esac
}
cale $1 $2 $3
[root@test2 ~]# /bin/bash 1.sh 5 + 4
5 + 4 = 9
状态返回
shell的函数返回值,也就是函数的退出状态。在shell中只有echo,reurn两种方式。
- 使用return返回,只能返回1--255的整数,函数使用retun返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败。
- 使用echo返回值,使用echo可以返回任何字符串结果,通常用于返回数据,比如一个字符串值或者列表。
//return返回值示例1
[root@test2 ~]# cat 2.sh
fun_echo_return() {
echo 100 #返回函数后执行后的数据
return 1 #返回函数执行后的状态码,通常放置在最后。
}
result=`fun_echo_return`
echo "函数的状态码是:$?"
echo "函数的状态返回值是$result"
[root@test2 ~]# /bin/bash 2.sh
函数的状态码是:1
函数的状态返回值是100
//return返回值示例2
[root@test2 ~]# cat 2.sh
fun_echo_return() {
return 1 #返回函数执行后的状态码,碰到retrun就会退出
echo 100 #返回函数后执行后的数据
}
result=`fun_echo_return`
echo "函数的状态是:$?"
echo "函数的状态返回值是$result"
[root@test2 ~]# /bin/bash 2.sh
函数的状态是:1
函数的状态返回值是 #这里面为空
//return返回值示例3,判断文件是否存在
[root@test2 ~]# cat 3.sh
file=/etc/passwd
t_file () {
if [ -f $file ];then
return 20
else
return 30
fi
}
t_file
if [ $? -eq 20 ];then
echo "文件存在"
elif [ $? -eq 30 ];then
echo "文件不存在"
fi
[root@test2 ~]# /bin/bash 3.sh
文件存在
//return返回值示例4,判断nginx是否在运行
[root@test2 ~]# !v
vim 4.sh
[root@test2 ~]# cat 4.sh
this_pid=$$
is_nginx_running(){
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &>/dev/null
if [ $? -eq 0 ];then
return 0
else
return 1
fi
}
is_nginx_running && echo "nginx is running" || echo "nginx is stoped"
[root@test2 ~]# /bin/bash 4.sh
nginx is stoped
return返回值示例5,猜数字游戏
-
如果用户输入的教值大于0且小于10则返回0
-
如果用户输入的数值大于等于10且小于20则返回1
-
如果用户输入的数值大于等于20且小于30则返回2
-
输入其余数值则返回3
[root@test2 ~]# cat 5.sh
checksum(){
read -p "请输入一个数字:" num
if [ $num -gt 0 -a $num -lt 10 ];then
return 0
elif [ $num -gt 10 -a $num -lt 20 ];then
return 1
elif [ $num -gt 20 -a $num -lt 30 ];then
return 2
else
return 3
fi
}
checksum
#根据函数返回值进行判断
if [ $? -eq 0 ];then
echo "你输入的数字是$num,大小0小于10"
elif [ $? -eq 1 ];then
echo "你输入的数字是$num,大小10小于20"
elif [ $? -eq 2 ];then
echo "你输入的数字是$num" 大小20小于30
fi
[root@test2 ~]# /bin/bash 5.sh
请输入一个数字:23
你输入的数字是23,大小10小于20
数组
什么是数组?
数据其实也是变量,传统的变量只能存储一个值,而数据可以存储多个值。
数组的分类?
shell数据分为普通数组和关联数组。
普通数组只能使用整数作为数据索引关联数据。
关联数组可以使用字符串作为数组索引。
普通数组
说白了数组就是能存储多个值的变量而已。
普通数组只能使用整数作为数据索引关联数据。
//一次赋予单个值,格式:数组名[索引]=变量值
[root@test2 ~]# array[0]=pear
[root@test2 ~]# echo ${array}
pear
[root@test2 ~]# array[3]=zhanghe
[root@test2 ~]# echo ${array[3]}
zhanghe
//一次赋予多个值
[root@test2 ~]# tt=(linux shell nginx test)
[root@test2 ~]# echo ${tt} #这么操作不对
linux
[root@test2 ~]# echo ${tt[0]} #显示数据的第一个数值,0就是变量的编号
linux
[root@test2 ~]# echo ${tt[1]} #显示数据的第二个数值
shell
[root@test2 ~]# echo ${tt[3]} #显示数据的第三个数值
test
[root@test2 ~]# echo ${tt[@]} #显示所有数值
linux shell nginx test
[root@test2 ~]# echo ${tt[*]} #显示所有数值
linux shell nginx test
[root@test2 ~]# echo ${!tt[*]} #显示下标,也称之为索引,索引就是变量的编号,普通数组的下标只能是整数
0 1 2 3
关联数组
关联数据要提前进行声明
//赋予单个值
[root@test2 ~]# declare -A zh
[root@test2 ~]# zh[xing]=zhang
[root@test2 ~]# echo ${zh[xing]}
zhang
//赋予多个值
[root@test2 ~]# declare -A info #声明关联数组info
//关联数组可以使用字符串作为数组索引,如下所示,name就是索引,而bgx就是值
[root@test2 ~]# info=([name]=bgx [age]=18 [skill]=linux)
[root@test2 ~]# echo ${info[name]}
bgx
[root@test2 ~]# echo ${info[age]}
18
[root@test2 ~]# echo ${info[skill]}
linux
[root@test2 ~]# echo ${info[@]}
bgx 18 linux
[root@test2 ~]# echo ${info[*]}
bgx 18 linux
[root@test2 ~]# echo ${!info[*]} #显示所有的下标
name age skill
//查看关联数组
[root@test2 ~]# declare -A | grep zh
declare -A zh='([xing]="zhang" )'
[root@test2 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
//通过数组元数的索引遍历,将统计的对象作为数据的索引,仅对关联数据
[root@test2 ~]# cat 6.sh
while read line
do
hosts[0]=10.0.0.1
hosts[1]=127.0.0.1
done < /etc/hosts
echo "查看数组的索引对应的值:${hosts[0]}"
for i in ${!hosts[@]}
do
echo hosts数组的索引$i,hosts数组的值${hosts[$i]}
done
[root@test2 ~]# /bin/bash 6.sh
查看数组的索引对应的值:10.0.0.1
hosts数组的索引0,hosts数组的值10.0.0.1
hosts数组的索引1,hosts数组的值127.0.0.1
改过一下上面的脚本。
root@test2 ~]# cat 6.sh
while read line
do
hosts[i++]=$line #这里改进了成了自增
done < /etc/hosts
echo "查看数组的索引对应的值:${hosts[0]}"
for i in ${!hosts[@]}
do
echo hosts数组的索引$i,hosts数组的值${hosts[$i]}
done
[root@test2 ~]# /bin/bash 6.sh
查看数组的索引对应的值:127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
hosts数组的索引0,hosts数组的值127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
hosts数组的索引1,hosts数组的值::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
统计次数
想统计什么次数,就将它取出来做为索引,然后让索引自增或自减。
例子:先演示使用awk统计次数,用awk做非常的简单,如下所示:
[root@test2 tmp]# cat sex.txt
jack m
alice f
tom m
rose f
robin m
bgx m
[root@test2 tmp]# awk '{print $2}' sex.txt
m
f
m
f
m
m
[root@test2 tmp]# awk '{print $2}' sex.txt | sort -r
m
m
m
m
f
f
[root@test2 tmp]# awk '{print $2}' sex.txt | sort -r | uniq -c
4 m
2 f
//下面演示一下通过数组来取函数,首先演示如何自增或自减
//声明变量sex
[root@test2 tmp]# declare -A sex
//设置数组sex,并在sex数组里面设置了两个索引和两个值
[root@test2 tmp]# sex=([m]=1 [f]=1)
//++代表自增
[root@test2 tmp]# let sex[m]++
[root@test2 tmp]# let sex[f]++
[root@test2 tmp]# echo ${sec[m]}
[root@test2 tmp]# echo ${sex[m]}
2
[root@test2 tmp]# echo ${sex[f]}
2
[root@test2 tmp]# cat sex.txt
jack m
alice f
tom m
rose f
robin m
bgx m
vim 2.sh
#!/bin/bash
declare -A info_sex
while read line
do
type=$(echo $line|awk '{print $2}')
let info_sex[$type]++
done<sex.txt
for i in ${!info_sex[@]}
do
echo "索引的名称是$i,索引的次数为${info_sex[$i]}"
done
//统计/etc/passwd的shell的数量
[root@test2 ~]# cat 8.sh
declare -A bash_type
while read line
do
type=$(echo $line | awk -F : '{print $NF}')
let bash_type[$type]++
done</etc/passwd
for i in ${!bash_type[@]}
do
echo "这种类型的$i,一共出现了${bash_type[$i]}次"
done
[root@test2 ~]# /bin/bash 8.sh
这种类型的/sbin/nologin,一共出现了18次
这种类型的/bin/sync,一共出现了1次
这种类型的/bin/bash,一共出现了8次
这种类型的/sbin/shutdown,一共出现了1次
这种类型的/sbin/halt,一共出现了1次
//统计nginx日志每个IP出现的次数,然而真正统计nginx的ip时,我们用的是awk
root@test2 tmp]# cat 4.sh
#!/bin/bash
declare -A ip_info
while read line
do
type=$(echo $line | awk '{print $1}')
let ip_info[$type]++
done < /var/log/nginx/access.log
for i in ${!ip_info[@]}
do
echo "ip是${i}出现了${ip_info[$i]}次"
done
[root@test2 tmp]# /bin/bash 4.sh
ip是127.0.0.1出现了1次
ip是192.168.80.6出现了4次
//统计tcp连接状态
[root@test2 ~]# !v
vim 7.sh
#!/bin/bash
declare -A tcp_status
ss_types=$(ss -an|awk '{print $2}')
for i in $ss_types
do
let tcp_status[$i]++
done
for j in ${!tcp_status[@]}
do
echo "索引名是:$j" 对应的次数是${tcp_status[$j]}
done
[root@test2 ~]# /bin/bash 7.sh
索引名是:ESTAB 对应的次数是89
索引名是:UNCONN 对应的次数是61
索引名是:State 对应的次数是1
索引名是:LISTEN 对应的次数是38