8月29日 脚本进阶3 函数

1、函数和shell程序的区别

Shell程序在子Shell中运行
而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改

[root@redhat7 script]#name=wang;func1 () { echo func1 is runing;echo $name;echo processid is $$; }
[root@redhat7 script]#func1
func1 is runing
wang
processid is 1410        ---函数是在当前shell中运行的,并没有开子进程
[root@redhat7 script]#echo $$
1410
[root@redhat7 script]#name=wang;func1 () { name=mage;echo func1 is runing;echo $name;echo processid is $$; }
[root@redhat7 script]#func1
func1 is runing
mage  ---因为函数执行的时候没有开子进程,所以会影响当前进程定义的变量,会对其进行修改。
processid is 1410
[root@redhat7 script]#echo $$
1410

2、查看定义的函数

[root@redhat7 script]#declare -f |grep -A 10 func1   ---declare -f可以查看所有定义的函数
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}
[root@redhat7 ~]#declare -f func1 ---可以不用过滤直接查看定义的函数
func1 () 
{ 
    declare -i num=100;
    echo func1 is runing;
    echo "func1:num=$num"
}
[root@redhat7 script]#set |grep -A 10 func1---set可以查看所有定义的函数和变量
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}

3、函数的组成部分

函数由两部分组成:函数名和函数体
help function
语法一:
function f_name{
...函数体...
}
语法二: ---- 此种方法是最常用的,系统自带的函数一般都是用这种方法定义的函数
function f_name(){
...函数体...
}
语法三:
f_name(){
...函数体

4、别名对函数的影响

[root@redhat7 script]#declare -f |grep func1 -A 5   ---之前定义过一个这样的函数
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}
[root@redhat7 script]#alias func1='ls -l'     ---将函数名定义为别名
[root@redhat7 script]#func1   ----当调用这个函数时,执行的是别名而不是函数本身
total 168
-rwxr-xr-x. 1 root root  156 Aug 24 18:59 192.sh
-rwxr-xr-x. 1 root root  390 Aug 25 08:23 21dengyao.sh

总结:定义别名之后函数就无法被调用了,所以一般将函数写到脚本里使用,因为脚本里面别名是不起作用的。

4、函数的使用

可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行
调用:给定函数名
函数名出现的地方,会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止

5、函数的退出状态码

(1) 默认取决于函数中执行的最后一条命令的退出状态码
(2) 自定义退出状态码,其格式为:
return 从函数中返回,用最后状态命令决定返回值,退出函数不可以用exit,exit会退出整个脚本,用return可以退出函数。
return 0 无错误返回。
return 1-255 有错误返回
函数和脚本的退出状态码保存到$?里
unset 函数名可以销毁函数和撤销变量的操作一样
set -- 销毁位置变量

6、在脚本中定义使用函数

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用
调用函数仅使用其函数名即可
示例

[root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
hello () {
        echo "Hello there today's date is `date +%F`"
}
echo "now going to function hello"
hello    ---要调用这个函数,使用函数名就可以
echo "back from the function"
[root@redhat7 script]#./func1.sh 
now going to function hello
Hello there today's date is 2017-08-29
back from the function

7、使用函数文件

[root@redhat7 script]#vim funcs   ----创建一个函数文件,注意函数文
件不是脚本,不用加#!/bin/bash
hello () {
        echo "Hello there today's date is `date +%F`"
 [root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
source funcs    ---先把函数文件载入到当前的脚本中,也可以用
. funcs,注意中间要有空格
echo "now going to function hello"
hello     ----然后调用这个函数
echo "back from the function"
[root@redhat7 script]#vim functions 
hello () {
        echo "Hello there today's date is `date +%F`"
}
add () {
       echo $[$1+$2]
}
osversion () {
            sed -r 's/.* ([0-9])\..*/\1/' /etc/redhat-release ---定义一个函
数,判断版本号
}
[root@redhat7 script]#. functions 
[root@redhat7 script]#osversion 
7
[root@redhat7 script]#[ `osversion` == 7 ]&&echo 7  ---调用这个函
数,进行判断,如果是7,就打印7
7

注意:如果函数文件和脚本文件不在同一个目录下,此时函数文件要写上全路径,比如source /root/funs。使用函数文件可以把经常使用的函数都放到一个函数文件里,使用的时候先载入这个函数文件,然后调用对应的函数就可以。

8、函数变量

变量作用域:
环境变量:当前shell和子shell有效
本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数
局部变量:函数的生命周期;函数结束时变量被自动销毁,只对函数内的变量有效。
在函数中定义局部变量的方法
local NAME=VALUE
示例

[root@redhat7 ~]#func1 () { local name=mage;echo func1 is runing;echo "func1:name=$name"; }
[root@redhat7 ~]#func1
func1 is runing
func1:name=mage
[root@redhat7 ~]#name=wang
[root@redhat7 ~]#echo $name    ---因为name在函数中被定义为局部
变量,只在函数中生效,所以不会影响当前shell中的变量
wang

总结:为了避免函数中的变量影响脚本中的其他变量,一般将函数中的变量定义为局部变量。

[root@redhat7 ~]#func1 () { declare -i num=100;echo func1 is runing;echo "func1:num=$num"; }  ---declare -i 作用是声明是整数,
但放到函数中声明是整数的同时,也将变量声明为局部变量,不影响
当前shell的变量
[root@redhat7 ~]#num=200
[root@redhat7 ~]#func1
func1 is runing
func1:num=100
[root@redhat7 ~]#echo $num
200
[root@redhat7 ~]#func1 () { declare -ig num=100;echo func1 is runing;echo "func1:num=$num"; }   ----如果要将函数内的变量定义为
全局变量也就是本地变量,可以使用-g选项
[root@redhat7 ~]#num=300
[root@redhat7 ~]#func1
func1 is runing
func1:num=100
[root@redhat7 ~]#echo $num
100

9、环境函数

[root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
hello  ---调用hello这个函数
[root@redhat7 script]#source /root/funcs ---先把用hello函数的funcs函数文件载入到当前shell中
[root@redhat7 script]#hello  ---在当前shell中调用这个函数,会执行
这个函数
Hello there today's date is 2017-08-29
[root@redhat7 script]#./func1.sh ---但执行脚本时调用这个函数就执
行不了,说明执行脚本时是开了一个当前shell的子进程,而hello这个
函数不在子进程里,所以无法调用
./func1.sh: line 3: hello: command not found
[root@redhat7 script]#export -f hello  ---声明hello这个函数是环境函
数,就可以将函数传给子进程,让子进程也可以使用,当然不声明也
可以,在当前脚本中再执行一次source /root/funcs,把函数文件载入到当前脚本
的shell中。
[root@redhat7 script]#./func1.sh 
Hello there today's date is 2017-08-29
[root@redhat7 script]#
还可以使用declare -xf 声明是环境函数,跟export -f一样。
declare -x 声明是环境变量=export

10、函数参数

函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfun carg1 arg2 ...”
在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量
但不能使用$0,$0表示带路径的当前脚本的名字,不能代表函数名,这一点和脚本不同,其他的参数调用和脚本都类似。
示例

[root@redhat7 script]#vim functions 
hello () {
        echo "Hello there today's date is `date +%F`"
}
add () {              ---定义一个函数,让传给函数的参数进行加运算
       echo $[$1+$2]
}
[root@redhat7 script]#vim func1.sh
#!/bin/bash
#
source functions
add 1 2   ---调用函数时加上参数
[root@redhat7 script]#./func1.sh ---执行结果
3

11、函数递归

函数直接或间接调用自身
注意递归层数
递归实例:
阶乘是基斯顿·卡曼于1808 年发明的运算符号,是数学术语
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1,自然数n的阶乘写作n!
n!=1×2×3×...×n
阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n
n!=n(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!

[root@redhat7 script]#vim jiecheng.sh 
#!/bin/bash
#
fact () {
      if [ $1 -eq 0 -o $1 -eq 1 ];then
             echo 1
      else
            echo $[$1*`fact $[$1-1]`]  ---函数自己调用自己
          fi
}
fact $1
[root@redhat7 script]#./jiecheng.sh 4
24

12、fork炸弹

fork炸弹是一种恶意程序,它的内部是一个不断在fork进程的无限循环,实质是一个简单的递归程序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源
函数实现
:(){ :|:& };:
bomb() { bomb | bomb & }; bomb
脚本实现

cat Bomb.sh
#!/bin/bash
./$0|./$0&   ---脚本调用脚本

13、如何实现打印正确和错误时显示ok和FAILED

[root@redhat7 script]#vim ok.sh
#!/bin/bash
#
. /etc/init.d/functions   ---将这个函数文件读入到当前脚本中
action "success! " true  ---调用函数文件里的action这个函数,其中true可以用任何返回结果为真的代替
action "failed"   false ---false可以用任何返回结果为假的代替
[root@redhat7 script]#./ok.sh
success!                                                   [  OK  ]
failed                                                     [FAILED]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容