Linux shell脚本之函数 Function 详解

Linux shell脚本之函数Function

  • 函数详解
    • 函数语法
    • 函数的生命周期
    • 函数返回值
    • 函数参数
    • 变量作用域
      • 1、本地变量
      • 2、局部变量
      • 函数变量示例
    • 函数递归
      • 递归示例
    • 函数示例

函数详解

在过程式编程中,代码会重用。过程式编程又分为:模块化编程和结构化编程。
把代码重用的代码段进行命名,并重复调用,这就是函数

函数(function):把一段独立功能的代码当作一个整体,并为之命名一个名字,成为命名的代码段,此即为函数。

在使用函数时,需要注意以下几点:

  • 1、定义函数的代码段在定义时是不会被执行的,在调用时才会被执行。
  • 2、在脚本中如果想要调用函数,在代码中给定函数名即可。
  • 3、函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码

函数语法

函数常用的语法格式有两种:

  • 语法格式一
function  f_name  {
	...函数体...
}
  • 语法格式二
f_name()  {
	...函数体...
}

函数的生命周期

函数的生命周期在被调用时开始,返回时终止。

其状态返回结果为函数体运行的最后一条命令的状态结果。当然也可以自定义状态返回结果。

  • 自定义函数的状态返回值,需要使用命令:return,格式如下:
    # return [0-255] ;其中 0 代表成功; 1~255 代表失败。
  • 函数执行过程中,只要遇到 return 就会终止执行,即使函数中还有未执行完的命令,类似于脚本中的 exit 。

大家一定要注意区分状态返回结果和状态返回值:

命令的返回结果:比如使用 ls 输出的内容列表
命令的状态返回值: 使用 # echo $? 进行查看。0 代表成功; 1~255 代表失败。

函数返回值

函数的返回值包括两个:

  • 1、函数的执行结果返回值
a、使用 echo 或者 printf 命令进行输出(printf 不会换行)
b、函数体中调用的命令的执行结果
  • 2、函数的退出状态码
a、默认取决于函数体中执行的最后一条命令的退出状态码
b、自定义:return 值

函数参数

函数可以接受函数,在函数体当中,可以使用 $1,$2,… 引用传递给函数的参数。也可以使用 $* 或 $@ 引用所有的参数,使用 $# 引用传递的参数的个数。
在调用函数时,在函数后面以空白符分隔给定参数列表即可,例如: testfunc arg1 arg2 arg3 …

但是一定要注意,脚本参数 和 函数参数 是两回事,可以通过以下示例进行了解。

1、添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给参数。

[root@LeeMumu ~]# bash userAdd10.sh JC
Add user JC1 finished.
Add user JC2 finished.
Add user JC3 finished.
Add user JC4 finished.
Add user JC5 finished.
Add user JC6 finished.
Add user JC7 finished.
Add user JC8 finished.
Add user JC9 finished.
Add user JC10 finished.
[root@LeeMumu ~]# cat userAdd10.sh 
#!/bin/bash
#
# 5:user exists
addusers() {
if id $1 &> /dev/null; then
	return 5
else
	useradd $1
	retval=$?
	return $retval
fi
}

for i in {1..10}; do
	addusers ${1}${i}                  # ${1}${i} 在这里对于函数 addusers 来说就是位置参数 $1 
	retval=$?
	if [ $retval -eq 0 ]; then
		echo "Add user ${1}${i} finished."
	elif [ $retval -eq 5 ]; then
		echo "user ${1}${i} exists."
	else
		echo "Unkown Error."
	fi
done

2、编写一个脚本,查看 192.168.1.1~192.168.1.254 之间哪些地址可以ping通。

[root@LeeMumu ~]# bash pING.SH 
Ping 192.168.1.1 successfully!
Ping 192.168.1.2 successfully!
... ...
[root@LeeMumu ~]# cat pING.SH 
#!/bin/bash
#
# 
pingtest() {
	if ping $1 -c 1 &> /dev/null ; then
		echo "Ping $1 successfully!"
	else
		echo "Ping $1 unsuccessfully!"
	fi
}

for i in {1..254}; do
	pingtest 192.168.1.$i              # 192.168.1.$i 在这里对于函数 pingtest 来说就是位置参数 $1 
done

3、打印NN乘法表。

[root@LeeMumu ~]# bash NN1.sh 2
1X1=1	
1X2=2	2X2=4	
[root@LeeMumu ~]# bash NN1.sh 3
1X1=1	
1X2=2	2X2=4	
1X3=3	2X3=6	3X3=9	
[root@LeeMumu ~]# bash NN1.sh 5
1X1=1	
1X2=2	2X2=4	
1X3=3	2X3=6	3X3=9	
1X4=4	2X4=8	3X4=12	4X4=16	
1X5=5	2X5=10	3X5=15	4X5=20	5X5=25	
[root@LeeMumu ~]# cat NN1.sh 
#!/bin/bash
#
#
NN() {
for ((i=1;i<=$1;i++));do
	for ((j=1;j<=i;j++));do
		echo -e -n "${j}X${i}=$[${i}*${j}]\t"
	done
	echo
done
}

NN $1

变量作用域

为了便于我们对函数的整体理解,我们在这儿对 本地变量局部变量 进行解释。

1、本地变量

本地变量的作用是是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell脚本程序文件。脚本执行时实在shell子进程里执行,脚本执行结束后,变量销毁。

变量赋值:name=value
变量引用:${name}, $name
	"":变量名会替换为其值;
	'':变量名不会替换为其值;
查看变量:set
撤销变量:unset name
	(注意:此处非变量引用;千万不能带 $ 符号,变量引用时才需要带 $ 符号)

2、局部变量

局部变量的作用域是函数的生命周期,在函数结束时被自动销毁。

局部变量赋值:local VARIABLE=VALUE

函数变量注意事项:

  • 1、函数结束不是脚本结束。
  • 2、函数里命令变量时,尽量定义为局部变量。
  • 3、函数里面可以调用本地变量,还可以对本地变量的值进行修改,会对自己脚本变量产生影响,所以在函数和主程序不进行交互的情况下,在函数里面尽量使用 local 定义局部变量。
可参考以下博客,有对脚本变量的详细解释:
	https://mp.csdn.net/mdeditor/95232625#bash_234

函数变量示例

通过以下示例,大家可以加强对函数变量的理解。
1、函数使用本地变量,会改变本地变量的值。

[root@LeeMumu ~]# bash fUNCTION1.sh  # 通过结果,可以得知通过调用函数改变了本地变量 
Function: jerry
Shell: jerry
[root@LeeMumu ~]# cat fUNCTION1.sh 
#!/bin/bash
#
name=tom                             # 定义本地变量 name=tom

setname() {
	name=jerry                       # 函数里定义本地变量  
	echo "Function: $name"           # echo 函数变量
}

	setname                          # 调用函数
	echo "Shell: $name"              # echo 本地变量    

2、函数使用本地变量,不会改变本地变量的值。

[root@LeeMumu ~]# bash fUNCTION2.sh  # # 通过结果,可以了解局部变量的作用域
Function: jerry
Shell: tom
[root@LeeMumu ~]# cat fUNCTION2.sh 
#!/bin/bash
#
name=tom                         

setname() {
 	local name=jerry                       
	echo "Function: $name"           
}

	setname                          
	echo "Shell: $name"              

函数递归

函数递归是指函数直接或间接调用自身。

递归示例

1、阶乘函数

[root@LeeMumu ~]# bash factTest.sh 1
1
[root@LeeMumu ~]# bash factTest.sh 2
2
[root@LeeMumu ~]# bash factTest.sh 3
6
[root@LeeMumu ~]# bash factTest.sh 11
39916800
[root@LeeMumu ~]# cat factTest.sh 
#!/bin/bash
#
#
fact() {
	if [ $1 -eq 0 -o $1 -eq 1 ] ;then
		echo 1
	else
		echo $[$1*$(fact $[$1-1])]    # () 代表命令引用  [] 代表公式
	fi
}

fact $1

2、斐波那契数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。

[root@LeeMumu ~]# bash fUNCTION3.sh 9
1 1 2 3 5 8 13 21 34 
[root@LeeMumu ~]# cat fUNCTION3.sh 
#!/bin/bash	
#
fab() {
	if [ $1 -eq 1 ]; then
		echo -n "1 "
	elif [ $1 -eq 2 ]; then
		echo -n "1 "
	else
		echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "
	fi
}

for i in $(seq 1 $1); do
	fab $i
done 
echo

函数示例

1、给定一个用户名,取得其用户的 id 号和默认的 shell 。

[root@LeeMumu ~]# bash idShell.sh user33 
1006:/bin/bash
[root@LeeMumu ~]# cat idShell.sh 
#!/bin/bash
#
userinfo() {
	if id "$username" &> /dev/null ; then
		grep "^$username\>" /etc/passwd | cut -d: -f3,7 
	else
		echo "No  Such User."
	fi
}

username=$1
userinfo 

2、编写服务框架脚本

#!/bin/bash
#
# chkconfig: - 50 50
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog

start() {
	if [ -f $lockfile ]; then
		echo "$prog is running yet."
	else
		touch $lockfile
		[ $? -eq 0 ] && echo "start $prog finshed."
	fi
}
stop() {
	if [ -f $lockfile ]; then
		rm -f $lockfile
		[ $? -eq 0 ] && echo "stop $prog finished."
	else
		echo "$prog is not running."
	fi
}
status() {
	if [ -f $lockfile ]; then
		echo "$prog is running"
	else
		echo "$prog is stopped."
	fi
}
usage() {
	echo "Usage: $prog {start|stop|restart|status}"
}

case $1 in
start)
	start ;;
stop)
	stop ;;
restart)
	stop
	start ;;
status)
	status ;;
*)
	usage
	exit 1 ;;
esac

你可能感兴趣的:(Linux学习笔记)