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)的主要内容,如果未能解决你的问题,请参考以下文章
基于arm linux的shell函数定义函数调用及函数返回值用法
基于arm linux的shell函数定义函数调用及函数返回值用法