Shell高级用法-----函数(function)

Posted 一叶知秋~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell高级用法-----函数(function)相关的知识,希望对你有一定的参考价值。

函数介绍(function用法)

1、function用法

1、函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。

2、它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运 行,而是shell程序的一部分,定义函数只对当前的会话窗口有效,如果再打开一个窗口再定义另外一个函数,就对另一个窗口有效,两者互不影响。

3、函数和shell程序比较相似,区别在于以下两种:

(1)Shell程序在子Shell中运行。

(2)而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改。

2、定义函数

函数由两部分组成:函数名和函数体

help function 
语法一:  f_name (){   
  ...函数体...  
} 
语法二:  function f_name { 
   ...函数体...  
}  
语法三:  function f_name () {   
   ...函数体...  
}

可以使用declare -F 选项进行查看所有定义的函数,用unset 加上变量名 就可以删除定义的变量

3、函数的定义和使用:

1、函数的定义和使用:

(1)可在交互式环境下定义函数

(2)可将函数放在脚本文件中作为它的一部分

(3)可放在只包含函数的单独文件中

2、调用:函数只有被调用才会执行

调用:给定函数名

函数名出现的地方,会被自动替换为函数代码

3、函数的生命周期:被调用时创建,返回时终止

4、函数返回值

函数有两种返回值:

1、函数的执行结果返回值:

(1) 使用echo等命令进行输出

(2) 函数体中调用命令的输出结果

 

 

2、函数的退出状态码:

(1) 默认取决于函数中执行的最后一条命令的退出状态码

(2) 自定义退出状态码,其格式为:

return 从函数中返回,用最后状态命令决定返回值:

  (1)return 0 无错误返回。

  (2)return 1-255 有错误返回

5、使用函数文件

1、可以将经常使用的函数存入函数文件,然后将函数文件载入shell

2、文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main

3、一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命 令查看所有定义的函数,其输出列表包括已经载入shell的所有函数

4、若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载 入此文件

6、删除shell函数

1、现在对函数做一些改动后,需要先删除函数,使其对shell不可用。使用unset命 令完成删除函数

2、命令格式为: unset function_name 

示例: unset findit

            再键入set命令,函数将不再显示

3、环境函数

(1)使子进程也可使用

(2)声明:export -f function_name

(3)查看:export -f 或 declare -xf

7、函数参数

函数可以接受参数: 传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;

例如“testfunc arg1 arg2 ...”

在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $# 等特殊变量

8、函数变量

变量作用域:

环境变量:当前shell和子shell有效

本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程; 因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数

局部变量:函数的生命周期;函数结束时变量被自动销毁

注意:如果函数中有局部变量,如果其名称同本地变量,使用局部变量

          在函数中定义局部变量的方法:local NAME=VALUE

 

实例1:

第一种写法:如果命令过多,这行执行不太方便

#!/bin/bash
func_os_version () {  # 定义一个function函数名为func_os_version,然后在大括号里边定义命令,取出操作系统的版本号,类似于定义别名一样
sed -nr ‘s/.* ([0-9]+)..*/1/p‘ /etc/redhat-release    
}
echo OS version is `func_os_version`  # 直接写上定义函数名称,或者用echo 加上反向单引号进行输出结果

查看输出结果:

[root@centos-7 ~]# bash osversion.sh 
OS version is 7

第二种写法:将定义的函数存放到文件中,并将要执行的脚本与定义的函数以及定义函数的文件名进行关联

[root@centos-7 ~]# cat functions   # 将定义的函数放到functions文件中
func_os_version () {
sed -nr ‘s/.* ([0-9]+)..*/1/p‘ /etc/redhat-release
}
[root@centos-7 ~]# cat osversion.sh  # 将要执行脚本的函数名和上面定义函数名的文件进行关联
#!/bin/bash
source functions  # source functions是关联上面的文件
func_os_version  # 关联functions里边定义的函数名
[root@centos-7 ~]# chmod +x osversion.sh   # 对脚本加上执行权限
[root@centos-7 ~]# ./osversion.sh   # 查看此时的执行结果即可
7

实例2:

第一步:先定义functions函数文件

[root@centos-7 data]# cat  functions  # 定义functions函数文件
func_is_digit(){
    if [ ! "$1" ];then  # 如果输入的信息不是空,就为真,但又不是数字
        echo "Usage:func_is_digit number"  # 请输入数字
        return  10 
    elif [[ $1 =~ ^[[:digit:]]+$ ]];then  # 如果输入是数字
        return 0  # return  0 返回的是正确结果,但是不会推出脚本
    else
        echo "Not a  digit"  # 如果上面都不是,就提醒不是数字
        return 1
    fi
}

第二步:调用functions函数文件,并对不同的成绩分段进行判断

[root@centos-7 data]# cat score.sh 
#!/bin/bash
source /data/functions  # 调用指定的函数文件的绝对路径
read -p "Input your score:" SCORE
func_is_digit $SCORE  # 直接调用上面的functions文件
if [ $? -ne 0 ];then   #判断上面的命令执行不等于0(不成功)就退出
    exit
else 
    if [ $SCORE -lt 60 ];then  # 如果成功了,对成绩的三种判断如下。
        echo "You are loser"
    elif [ $SCORE -lt 80 ];then
        echo "soso"
    else 
        echo "very good"
    fi
fi

实例3

生产中function配合case语法:

#!/bin/bash
#Author:  liupengju
#date:    2020-06-22
#TEL:     xxxxxxxxxx
#代码发布与回滚
set -e
set -u

#adx代码部署变量定义
ADX_DIR=/gnome/adx
adx_new_version="gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar"
ADX_NEW_MD5=`md5sum $adx_new_version | awk ‘{ print $1 }‘`

#此行需要修改为cf平台的md5码
ADX_CHK_MD5="43bcfe7594f083a8653126e0896b93ac" 

#directAd代码部署变量定义
direct_DIR=/gnome/directAd/
direct_version="direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar"
direct_MD5=`md5sum $direct_version | awk ‘{ print $1 }‘`
#direct_old_version=$(ls -l  |tail -n1 | awk ‘{print $9}‘)

#此行需要修改为cf平台的md5码
direct_CHK_MD5="03c3c2fc62b2edfc92e548351010ee9f"

##########部署directAd代码#############################
fun_copy_direct_code(){
	mv $direct_DIR/$direct_version  $direct_DIR/bak/${direct_version}_$(date +"%F-%T") 
        echo "-----上一个版本已经移动到备份目录"
	cp /data/$direct_version  $direct_DIR  && echo "-----代码复制成功!!!"
}

fun_chk_direct_code(){
      if [[ "$direct_MD5" == "$direct_CHK_MD5" ]];then
           echo "-----代码校验成功" && echo "代码部署成功后MD5值为:$direct_MD5"
      else
           echo "-----代码校验失败" && exit
      fi
}

fun_deploy_direct_restart(){
	#$direct_DIR/restart.sh
	systemctl restart httpd
	systemctl restart nginx
	echo "后端服务重启成功!!!"
}

fun_chk_direct_port1(){ 
#验证端口存活状态
	PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
	PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
     for port in $PORT1 $PORT2;do
        echo "The port is:$port------监听端口正常"
     done
}

#############回滚direct代码###################################
fun_rollback_direct_code(){
	cd $direct_DIR/bak
	direct_old_version=$(ls -l  |tail -n1 | awk ‘{print $9}‘)  # 提取上一个版本的jar包
	mv $direct_DIR/${direct_version} $direct_DIR/bak/${direct_version}_$(date +"%F-%T")
	mv $direct_DIR/bak/${direct_old_version} $direct_DIR/${direct_version}
	echo "------旧版本代码移动成功"
	direct_old_MD5=$(md5sum $direct_DIR/${direct_version} |  awk ‘{print $1}‘)
	echo "代码回滚后MD5值为:$direct_old_MD5"
}

fun_rollback_direct_restart(){
	#$direct_DIR/restart.sh
	systemctl restart httpd
	systemctl restart nginx
	echo "--------后端服务重启成功"
}

fun_chk_direct_port2(){
#验证端口存活状态
	PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
	PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
    for port in $PORT1 $PORT2;do
        echo "The port is:$port------端口监听正常"
    done
}


#####################adx代码部署########################################
fun_copy_adx__code(){
	mv $ADX_DIR/$adx_new_version  $ADX_DIR/bak/${adx_new_version}_$(date +"%F-%T") 
        echo "-----上一个版本已经移动到备份目录"
	cp /data/$adx_new_version  $ADX_DIR  && echo "-----代码复制成功!!!"
}

fun_chk_adx_code(){
	if [[ "$ADX_NEW_MD5" == "$ADX_CHK_MD5" ]];then
		echo "-----代码校验成功" && echo "代码部署成功后MD5值为:$ADX_NEW_MD5"
	else
        	echo "-----代码校验失败" && exit
	fi 
}

fun_deploy_adx_restart(){
#$ADX_DIR/restart.sh
	systemctl restart httpd
	systemctl restart nginx
	echo "后端服务已经启动!!!"
}

#验证端口存活状态
fun_chk_adx_port1(){
	PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
	PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
      for port in $PORT1 $PORT2;do
    	  echo "The port is:$port------监听的端口正常启动"
      done
}


###################################adx代码回滚###########################
fun_rollback_adx_code(){
	cd $ADX_DIR/bak
	adx_old_version=$(ls -l  |tail -n1 | awk ‘{print $9}‘)
	mv $ADX_DIR/${adx_new_version} $ADX_DIR/bak/${adx_new_version}_$(date +"%F-%T")
	mv $ADX_DIR/bak/${adx_old_version} $ADX_DIR/${adx_new_version}
	echo "------旧版本代码移动成功"
	adx_old_MD5=$(md5sum $ADX_DIR/${adx_new_version} |  awk ‘{print $1}‘)
	echo "代码回滚后MD5值为:$adx_old_MD5"
}

fun_rollback_adx_restart(){
	#$ADX_DIR/restart.sh
	systemctl restart httpd
	systemctl restart nginx
	echo "--------后端服务已经启动"
}

fun_chk_adx_port2(){
#验证端口存活状态
	PORT1=`ss -nlt|grep 8080 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
	PORT2=`ss -nlt|grep 8182 |awk -F"[[:space:]]+|:" ‘{ print $7}‘`
    for port in $PORT1 $PORT2;do
        echo "The port is:$port-------端口监听正常"
    done
}

case $1 in
  direct_deploy)
     fun_copy_direct_code
     fun_chk_direct_code
     fun_deploy_direct_restart
     fun_chk_direct_port1
     ;;
  direct_rollback)
     fun_rollback_direct_code
     fun_rollback_direct_restart
     fun_chk_direct_port2
     ;; 
  adx_deploy)
     fun_copy_adx__code
     fun_chk_adx_code
     fun_deploy_adx_restart
     fun_chk_adx_port1
     ;;
  adx_rollback)
    fun_rollback_adx_code
    fun_rollback_adx_restart
    fun_chk_adx_port2
     ;;
esac

实例4:

#!/bin/bash
#Auth:   liupengju
#TEL:    xxxxx
########部署完成校验#######

####验证adserver版本号#############
fun_chk_adx_version(){
	ansible adx -m shell -a ‘md5sum   /gnome/adx/gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar‘ |awk ‘{print $1}‘|sort |head -n62 |tee version_adx |cat -n
	adx_version=$(ansible adx -m shell -a ‘md5sum /gnome/adx/gnome-adx-0.0.1-SNAPSHOT-jar-with-dependencies.jar‘ |awk ‘{print $1}‘|sort |tail -n62 |uniq -c|awk ‘{print $2}‘)
	echo -e "e[1;32m新发布的版本号为:$adx_versione[0m"
	version1=$(diff metadata  version_adx)
        if [ -z $version1 ];then
    	   echo -e "e[1;32m代码部署成功 e[0m"
	else
    	   echo -e "e[1;31m请检查错误  e[0m"
	fi
}

####验证directAd版本号############
fun_chk_direct_version(){	
        ansible adx -m shell -a ‘ md5sum   /gnome/directAd/direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar‘|awk ‘{print $1}‘|sort |head -n62 |tee version_direct |cat -n
        direct_version=$(ansible adx -m shell -a ‘md5sum /gnome/directAd/direct-ad-0.0.1-SNAPSHOT-jar-with-dependencies.jar‘|awk ‘{print $1}‘|sort |tail -n62 |uniq -c|awk ‘{print $2}‘)
        echo -e "e[1;32m新发布的版本号为:$direct_versione[0m"
        version2=$(diff metadata  version_direct)
        if [ -z $version2 ];then
           echo -e "e[1;32m代码部署成功 e[0m"
        else
           echo -e "e[1;31m请检查错误  e[0m"
        fi
}

###验证8080端口状态###############
fun_chk_8080_port(){
 	chk_ip_8080=$(ansible adx -m shell -a ‘ netstat -ntulp |grep 8080‘ |awk ‘{print $1}‘ |egrep "[0-9]+.*" |sort | tee data_8080.bak |cat -n)
	DIR_8080=$(diff metadata  data_8080.bak)
	if [ -z $DIR_8080 ];then
    	   echo -e "e[1;32m端口检查成功,端口号:8080 e[0m"
	else
    	   echo -e "e[1;31m请检查错误  e[0m"
	fi
}

####验证8182端口状态#############
fun_chk_8182_port(){
	chk_ip_8182=$(ansible adx -m shell -a ‘ netstat -ntulp |grep 8182‘ |awk ‘{print $1}‘ |egrep "[0-9]+.*" |sort |tee data_8182.bak |cat -n)
	DIR_8182=$(diff metadata  data_8182.bak)
	if [ -z $DIR_8182 ];then 
	    echo -e "e[1;32m端口检查成功,端口号:8182 e[0m"
	else
	    echo -e "e[1;31m请检查错误  e[0m"
	fi
}

case $1 in
     adx)
       fun_chk_adx_version
       fun_chk_8080_port
       fun_chk_8182_port
       ;;
     direct)
       fun_chk_direct_version
       fun_chk_8080_port
       fun_chk_8182_port
       ;;
esac

  

 

以上是关于Shell高级用法-----函数(function)的主要内容,如果未能解决你的问题,请参考以下文章

2.shell编程-函数的高级用法

基于arm linux的shell函数定义函数调用及函数返回值用法

基于arm linux的shell函数定义函数调用及函数返回值用法

基于arm linux的shell函数定义函数调用及函数返回值用法

跟着360架构师 学习Shell脚本编程 完整版

Python的5种高级用法