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, ...调用这些参数;还可以使用[email protected], $*, $# 等特殊变量

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 加上反向单引号进行输出结果

查看输出结果:

[[email protected] ~]# bash osversion.sh 
OS version is 7

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

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

实例2:

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

[[email protected] 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函数文件,并对不同的成绩分段进行判断

[[email protected] 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_version\e[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_version\e[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)


推荐文章
在Linux下播放与录制电视

最近,在自己的Debian7.264位系统上成功安装了圆刚AverMediaC725B视频卡驱动。于是,可以使用mplayer与mencoder来看电视与录节目了。其中,用于播放电视的命令如下: 

如何删除Mac 的启动台(应用)残留的图标

如何删除MacOs启动台(应用)残留的图标方法很简单,删除“启动台”数据库里对应app的信息即可忘记什么版本的时候以前在“应用程序”删除应用后,启动台自动更新删掉不知道什么时候开始,直接在“应用程序”

《鸟哥linux》--第十一章课后习题答案

1.在linux上可以找到哪些shell?哪个档案记录可用的shell?儿linux预设的shell是?  1./bin/bash,/bin/tcsh,/bin/csh  2./etc/shells 

【原创】Linux中断子系统(四)-Workqueue

背景 Readthefuckingsourcecode!--By鲁迅 Apictureisworthathousandwords.--By高尔基 说明: Kernel版本:4.14 ARM64处理器,

关于在linux系统下安装jdk

    今天装jdk遇到了不少的问题,我第一次遇到64位虚拟机中居然装32位操作系统,然后遇到一系列的麻烦,差点有种崩溃的感觉; 对于版本为题是一个很关键的问题,对于jdk安装,不要认为只要java

【Linux】crontab 每隔1小时 2小时的执行job写法

crontab-l crontab-e   每五分钟执行 */5**** 每小时执行    0**** 每2小时执行    0*/2*** 每天执行       00*** 每周执行  

Mac进行一些操作时提醒Operation not permitted的完美解决

Mac版本10.14.5,向下向上都行:    1.关闭mac的安全机制,首先可以在正常模式下,输入csrutilstatus命令,查看mac安全机制是否开启。    2.如果Protectionst

linux系统开启秘钥认证登录详解

本文以已经产生好私钥和公钥为前提去讲述后续的增加秘钥认证的步骤:(秘钥的生成工具为:ssh-keygen,命令执行完后会在当前用户的家目录中生成了一个.ssh的隐藏目录,内含两个密钥文件。id_rsa

Linux下 boost库编译并加入到环境变量

1、下载源码:http://www.boost.org/2、tarzxvfboost_1_70_0.tar.gz3、cdboost_1_70_04、./bootstrap.sh--with-libra

Linux下设置环境变量

setenv(setenvironment variable)功能说明:查询或显示环境变量。语  法:setenv [变量名称][变量值]补充说明:setenv为tsch中查询或设置环境变量的指令。

Ubuntu编译配置Opencv

一、1.下载opencv源代码2.安装编译依赖库 2.1 sudoapt-getupdate 2.2 sudoapt-getinstallcmakesudoapt-getinstalllibgtk2.

ubuntu配置静态路由及重启生效

ubuntu配置静态路由及重启生效第一种方法:使用route命令(添加临时路由)添加到主机的路由#routeadd-host192.168.1.123deveth0#routeadd-host192.

Linux # kubuntu 14.04 登陆界面乱码,停止,进不了系统

问题描述:             kubuntu14.04登陆界面乱码,停止,进不了系统分析思路: 解决过程: 问题总结: 参考: lubuntu登陆界面乱码,如何解决?-查看主题?Ubuntu中

(赵小明RHCE笔记)linux基础之一

默认情况下,linux有一个图形界面,五个文本虚拟终端[email protected]#tty 用来查看当前是在哪个tty下ctrl+alt+F1-F7用来切换不同终端startx命令用来启动图形化

linux详解sudoers

sudo使用  Linux是多用户多任务的操作系统,共享该系统的用户往往不只一个。出于安全性考虑,有必要通过useradd创建一些非root用户,只让它们拥有不完全的权限;如有必要,再来提升权限执行。

关于eclipse的Description:Resource Path Location Type The project cannot be built until build path errors are resolved的问题

问题如上一开始安装也有问题,安装完打不开显示出错,打开eclipe的安装目录,找到eclipse.ini,在最后加上后面这么一行就好了。--add-modules=ALL-SYSTEM百度了一下,发现

Linux系统root密码修改

   重启系统。   进入系统引导界面:      按下e键:      选择第二项,内核启动参数设置,按下e键:      在结尾处,输入数字1或者英文"single",再回车:      按下b键

kali linux 2019.4设置为中文方法

就在前天,2019年11月26日,kaliLinux官网发布了最新版本:KaliLinux2019.4发行版,此版本和之前相比变动很大,系统界面、主题、壁纸都灿然一新。Kali Linux2019.4

Linux编程:--消息队列(MessageQueue)相关概念和原理

 一、消息队列概述消息队列(MessageQueue,简称为MQ)其本质是就是个队列,FIFO先进先出,只不过是队列中储放的主要内容是message,因而叫消息队列主要用于:不同的服务server、进

Ubuntu20.4安装

官网下载镜像https://releases.ubuntu.com/20.04/ubuntu-20.04-live-server-amd64.iso挂载开装选语言选键盘网络设置DHCP到地址代理设置空