函数和数组

[TOC]

函数

函数基础

什么是函数?

函数其实就是一堆命令的合集,用来完成特定功能的代码块,你可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数,要使用定义的函数,只需要填写函数名就可以了。

函数的作用?

使用函数可以让代码模块化,便于代码的复用,同时增加脚本的可读性。

函数和变量类似,必须先定义才可调用,如果定义不调用则不会被执行。

如何调用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方式。

  1. 函数传参示例,使用变量的方式传递固定值。
[root@test2 tmp]# cat 2.sh
fun_1(){
	echo "$sum"
}

sum=10
fun_1
[root@test2 tmp]# /bin/bash 2.sh
10
  1. 函数传参示例,使用变量方式传递可变的值
[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两种方式。

  1. 使用return返回,只能返回1--255的整数,函数使用retun返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败。
  2. 使用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,猜数字游戏

  1. 如果用户输入的教值大于0且小于10则返回0

  2. 如果用户输入的数值大于等于10且小于20则返回1

  3. 如果用户输入的数值大于等于20且小于30则返回2

  4. 输入其余数值则返回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
posted @ 2020-03-24 21:23  张贺贺呀  阅读(227)  评论(0编辑  收藏  举报