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]