做为一个经常写脚本的运维人员来讲,都能发现一个问题,很多时候我们在不同的脚本里面重复的写着同一段代码。比如我们要去使用正则表达式去判断IP地址的合法性问题,如果每次都去写一遍这个匹配IP的表达式,整个表达式写下来老长老长的,0-9的数字组合看的眼都花了,是不是很累了。当然有人会说了,保存一份正确的代码之后,需要用这段代码的时候,直接粘贴到正在编写的脚本里面不就行了嘛!是没错,但这样是不是很多脚本里面都重复存放着同一段代码,额外增加了脚本的代码量。有没有一个两全其美的办法,让我们的脚本代码量又小,又省去了每次重复的粘贴同一段代码的操作,同时还能完美的调用这段代码了。shell函数的出现为我们完美的解决了这一设想。
函数介绍
函数(function)是由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
函数和shell程序的区别:
Shell程序在子Shell中运行
而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改
定义函数的语法格式:
函数由两部分组成:函数名和函数体
语法一:
function f_name {
...函数体...
}
语法二:
function f_name () {
...函数体...
}
语法三:
f_name (){
...函数体...
}
函数的定义方式:
1,可在交互式环境下直接定义函数,当前shell环境可调用
2,可将函数定义在脚本文件中作为它的一部分,只可自己调用
3,可写成单独的函数库文件中,任何脚本都可以调用
函数的撤销方式:unset 函数名
函数的调用方式:
1,调用函数库中的函数时,首先得用source或.载入函数库文件,再指定要调用的函数名
注意:<点> <空格> <函数库文件名>文件名要带正确路径
2,命令行定义的、脚本自身定义的,直接指定要调用的函数名即可
函数名出现的地方,会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止
修改已定义的函数:
1,使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数
2,用unset命令从shell中删除函数;改动完毕后,再重新载入此函数或函数库文件
函数返回值
函数有两种返回值:
1,函数的执行结果返回值:
(1) 使用echo或printf命令进行输出
(2) 函数体中调用命令的输出结果
2,函数的退出状态码:
(1) return:默认取决于函数中执行的最后一条命令的退出状态码
(2) return #:自定义退出状态码,其格式为:
return 0 无错误返回
return 1-255 有错误返回
交互式环境下定义和使用函数
示例代码:
dir() {
> ls -l
> }
定义该函数后,若在命令行键入dir,其显示结果同ls -l的作用
该dir函数将一直保留到用户从系统退出,或执行了unset命令:unset dir
在脚本中定义及使用函数
函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用
调用函数仅使用其函数名即可
示例代码:
#!/bin/bash
maxnum () {
if [[ $1 -gt $2 ]];then
max=$1
min=$2
elif [[ $1 -lt $2 ]];then
min=$1
max=$2
fi
echo maxnum is : $max
echo minnum is : $min
}
maxnum 100 200
建立函数库存文件
示例代码:
#!/bin/bash
#Author:wangjun
#Contact QQ:183530300
#Version:1.0
#Create time:2016-08-18 14:58:52
#Description:founction lib
#maxnum and minnum
maxnum () {
if [[ $1 -gt $2 ]];then
max=$1
min=$2
elif [[ $1 -lt $2 ]];then
min=$1
max=$2
fi
echo maxnum :$max
echo minnum :$min
}
#operation
operation () {
let sum=$[$1+$2]
echo "$1 $2 sum is : $sum"
let reduce=$[$1-$2]
echo "$1 $2 reduce is : $reduce"
let product=$[$1*$2]
echo "$1 $2 product is : $product"
let quotient=$[$1/$2]
echo "$1 $2 quotient is : $quotient"
}
函数参数(函数可以接受参数):
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 ...”
在函数体中当中,可使用 $1,$2,...这些位置变量;还可以使用 [email protected],$*,$# 等特殊变量
函数变量
变量作用域:
环境变量:当前shell和子shell有效
本地变量:只在当前shell进程有效,执行脚本时会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本,包括脚本中的函数
局部变量:函数的生命周期内有效;函数结束时变量被自动失效
注意:如果函数中有局部变量,其名称同本地变量,局部变量会覆盖本地变量
在函数中定义局部变量的方法:local NAME=VALUE
函数递归:函数直接或间接调用自身
递归实例:
阶乘是基斯顿·卡曼于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)!
定义标准递归函数:
示例代码:
recursive () {
if [ $1 -eq 0 -o $1 -eq 1 ];then
echo 1
else
echo $[$1*$(recursive $[$1-1])]
fi
}
注意递归层数:shell环境下递归最大支持25,超过25的递归shell就无法计算并表示出来了
脚本中调用函数应用实例:
用户管理需要调用的函数库文件
[[email protected] fun]# cat function
#!/bin/bash
#Author:wangjun
#Contact QQ:183530300
#Version:1.0
#Create time:2016-08-18 14:58:52
#Description:founction lib
adduser () {
read -p "Please input a new username : " user
! id $user &> /dev/null && useradd $user &> /dev/null && echo "$user user add success" || echo "$user user exists"
}
deluser () {
read -p "Please input a exists username : " user
id $user &> /dev/null && userdel -r $user &> /dev/null && echo "$user user delet success" || echo "$user user doesn‘t exist"
}
addgroup () {
read -p "Please input a new groupname : " group
! (getent group | grep "^$group\>") &> /dev/null && groupadd $group &> /dev/null && echo "$group group add success" || echo "$group group exists"
}
delgroup () {
read -p "Please input a exists groupname : " group
getent group | grep "^$group\>" &> /dev/null && groupdel $group &> /dev/null && echo "$group group delet success" || echo "$group group doesn‘t exist"
}
调用函数库实现用户管理的脚本
[[email protected] fun]# cat useradmin.sh
#!/bin/bash
#Author:wangjun
#Contact QQ:183530300
#Version:1.0
#Create time:2016-08-18 19:29:03
#Description:User admin function test
. function
PS3="Please choice : "
select choose in "add user" "delet user" "add group" "delet group" "exit"
do
case $choose in
"add user")
adduser
;;
"delet user")
deluser
;;
"add group")
addgroup
;;
"delet group")
delgroup
;;
exit)
exit
;;
esac
done
[[email protected] fun]#
执行效果如图所示:
通过这个实例,我们不难发现,调用函数写出来的脚本代码量又小,看起来相当清析,提前定义好的函数集中存放至自己的函数库中,日后调用起来是不是也非常省事了。关于函数就先分享到这儿,简单的应用应该没问题了。当然后续会随时更新。