• 函数和数组


    -=======================================================================
    张贺,多年互联网行业工作经验,担任过网络工程师、系统集成工程师、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方式。

    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
    
  • 相关阅读:
    【20211012】以确定去适应不确定
    【20211011】工作之余
    【20211009】二孩的心思
    【20211010】幸福声响
    【20211007】连岳摘抄
    【读书笔记】《创新与企业家精神》
    【20211006】连岳摘抄
    【20211008】生活规律,事情也好解决
    ASP.NET中DataGrid的简单用法
    无限级分类的实现
  • 原文地址:https://www.cnblogs.com/yizhangheka/p/12562139.html
Copyright © 2020-2023  润新知