九、Shell之函数
一、shell的函数介绍
函数的作用就是将程序里多次被调用的相同代码组合起来(函数体),并为其取一个名字(即函数名),其他所有想重复调用这部分代码的地方都只需要调用这个名字就可以了。当需要修改这部分重复代码时,只需要改变函数体内的一份代码即可实现对所有调用的修改,也可以把函数独立地写到文件里,当需要调用函数时,再加载进来使用。
使用Shell函数的优势:
1、把相同的程序段定义成函数,可以减少整个程序的代码量,提升开发效率。 2、增加程序的可读性、易读性,提升管理效率。 3、可以实现程序功能模块化,使得程序具备通用性(可移植性)。
二、shell函数的格式及执行
1、函数的格式
方法一: function 函数名(){ 指令集 return n } 方法二: 函数名(){ 指令集 return n }
2、函数的执行方法
funcation 函数名(){ 指令集 return n } 函数名 重要说明: 1、执行Shell函数时,函数名前的function和函数后的小括号都不要带。 2、函数的定义必须在要执行的程序前面定义或加载。 3、Shell执行系统中各种程序的执行顺序为:系统别名→函数→系统命令→可执行文件。 4、函数执行时,会和调用它的脚本共用变量,也可以为函数设定局部变量及特殊位置参数。 5、在Shell函数里面,return命令的功能与exit类似,return的作用是退出函数,而exit是退出脚本文件。 6、return语句会返回一个退出值(即返回值)给调用函数的当前程序,而exit会返回一个退出值(即返回值)给执行程序的当前Shell。 7、如果将函数存放在独立的文件中,被脚本加载使用时,需要使用source或“.”来加载。 8、在函数内一般使用local定义局部变量,这些变量离开函数后就会消失。
2)带参数的函数执行方法
funcation 函数名(){ 指令集 return n } 函数名 参数1 参数2 函数后接参数的说明: 1、Shell的位置参数($1、$2…、$#、$*、$?及$@)都可以作为函数的参数来使用。 2、此时父脚本的参数临时地被函数参数所掩盖或隐藏。 3、$0比较特殊,它仍然是父脚本的名称。 4、当函数执行完成时,原来的命令行脚本的参数即可恢复。 5、函数的参数变量是在函数体里面定义的。
#! /bin/bash function ywx() { echo ywx } king() { echo king } ywx #调用ywx函数 king #调用king函数
测试脚本
[root@node1 scripts]# bash hanshu1.sh ywx king
更改脚本如下:
#! /bin/bash function ywx() { echo ywx } ywx king #只定义ywx函数,不定一king函数
测试脚本
[root@node1 scripts]# bash hanshu1.sh ywx hanshu1.sh: line 9: king: command not found #没有定义的king函数会被认为是一个命令来执行,king命令不存在的
在写函数时,可以把函数写在系统的函数文件中(/etc/init.d/functions)。
在需要函数时,只需要加载该函数文件,即可调用该文件中的所有函数。
把hello_world函数添加到函数文件中
[root@node1 scripts]#cat /etc/init.d/functions ......省略 hello_world() { echo "ni hao world!!!" } #注意:函数需要加载下面内容的前面 # A sed expression to filter out the files that is_ignored_file recognizes __sed_discard_ignored_files='/\(~\|\.bak\|\.old\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d' if [ "$_use_systemctl" = "1" ]; then if [ "x$1" = xstart -o \ "x$1" = xstop -o \ "x$1" = xrestart -o \ "x$1" = xreload -o \ "x$1" = xtry-restart -o \ "x$1" = xforce-reload -o \ "x$1" = xcondrestart ] ; then systemctl_redirect $0 $1 exit $? fi fi strstr "$(cat /proc/cmdline)" "rc.debug" && set -x return 0
在脚本中直接调试函数文件中的函数
#! /bin/bash . /etc/init.d/functions #在脚本中调用函数文件 hello_world #调用函数文件中的"hello_world函数"
测试脚本
[root@node1 scripts]# bash hanshu2.sh ni hao world!!!
案例1:
#! /bin/bash hello_world() { echo "ni hao $1" } hello_world china #调用函数后面紧跟的参数为定义函数时,其中的$1
测试脚本
[root@node1 scripts]# cat /scripts/hanshu3.sh #! /bin/bash hello_world() { echo "ni hao $1" } hello_world china [root@node1 scripts]# bash /scripts/hanshu3.sh ni hao china
案例2:
#! /bin/bash hello_world() { echo "ni hao $1" } hello_world $1 #该处的$1为脚本参数$1,把脚本参数的$1传递给了函数里面的$1
测试脚本
[root@node1 scripts]# cat /scripts/hanshu4.sh #! /bin/bash hello_world() { echo "ni hao $1" } hello_world $1 [root@node1 scripts]# bash hanshu4.sh chinese #脚本的$1参数传递给了函数中的$1 ni hao chinese
使用函数编写url的检查
#! /bin/bash #配置Usage函数 Usage() { echo "Usage $0 url" } #配置url_check函数 url_check() { curl $1 &> /dev/null #wget --spider -q -o /dev/null --tries=1 -T 5 $1 #curl的命令2选1即可 if [ $? -eq 0 ];then echo "$1 is running ok!" else echo "$1 is false!" fi } main() { if [ $# -ne 1 ];then Usage #<==调用Usage函数 exit 1 fi url_check $1 #<==调用url_check函数,接收函数的传参,即把下文main结尾的$*传到这里。 } main $* #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,是一种常用手法。
测试脚本
[root@node1 scripts]# sh url_check.sh www.baiduddd www.baiduddd is false! [root@node1 scripts]# sh url_check.sh www.baidu.com www.baidu.com is running ok! [root@node1 scripts]# sh url_check.sh www.baidu.com www.ywx.com Usage url_check.sh url
引用/etc/init.d/functions函数文件
#! /bin/bash . /etc/init.d/functions #引用functions文件 #配置Usage函数 Usage() { echo "Usage $0 url" } #配置url_check函数 url_check() { curl $1 &> /dev/null #wget --spider -q -o /dev/null --tries=1 -T 5 $1 #curl的命令2选1即可 if [ $? -eq 0 ];then action "$1 is running ok!" /bin/true #调用functions中的action函数 else action "$1 is false!" /bin/false #调用functions中的action函数 fi } main() { if [ $# -ne 1 ];then Usage #<==调用Usage函数 exit 1 fi url_check $1 #<==调用url_check函数,接收函数的传参,即把下文main结尾的$*传到这里。 } main $* #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,是一种常用手法。
测试脚本:
I have a dream so I study hard!!!