函数是什么?
函数是一些命令的集合,使用一个名称做代表,称为函数名称。函数名称的命名规则和变量相同。
一旦函数定义好了,执行这个名称,就好象执行Bash的命令一样,称为调用函数。实际上,Bash调用函数时,会执行函数里的命令区域,执行
完毕,Bash会回到调用函数的下一行继续执行。
函数的最大作用是可以让程序模块化。如果Script程序中,需要重复执行某一命令区域,那么就应当使用函数代表这个区域,一方面可使程序精简,一方面程序代码页比较容易维护。
一、函数的用法
1、函数的语法
语法1:
function 函数名称()
{
命令区域
}
函数名称与()之间可以直接相连,也可用空格隔开。
语法2:
函数名称()
{
命令区域
}
关键词function可省略
语法3:
function 函数名称
{
命令区域
}
如果使用关键词function,函数名称后的()也可省略
例子:
#!/bin/bash
getline () #定义函数getline,用来定义文件行数
{
local i=0 #i代表已计算的行数,先归0。
#local用来设定变量i是getline函数中专有的变量,不影响script其它地方也叫i的函数
while read line
do #使用while循环,自变量值$file指定文件读取每一行
let ++i #每读一行 变量i值+1
done < $file #使用转向输入,让read能由$file读取数据
echo "$file文件共有$i行" #显示总行
}
file=$1 #由命令行第一个参数,取得要计算行数的文件名。
getline #调用getline函数
echo "getline 执行完毕" #getline执行完后,回到这里继续执行下一指令。
#./script passwd
passwd文件共有36行
getline执行完毕
在调用函数之前一定要先定义该函数。
unset -f 函数 取消函数
2、函数的结束状态
执行函数时,函数中最后一个命令的传回值代表函数的结束状态。执行函数如果遇到return命令,就立即结束,回到调用函数的下一个命令,此时函数的传回值为0
#!/bin/bash
getline ()
{
local i=0
while read line
do
let ++i
if (($i > 10));then #判断是否超过10行
echo "$file文件大于10行,不再继续"
return #遇到return命令,立即回到echo$?所在行
#默认传回值为0,也可指定不同的传回值,直接在return空格加数字即可
fi
done < $file
echo "$file文件共有$i行"
}
file=$1
getline
echo $?
echo "getline 执行完毕"
可以根据$?(return 接的数字n )的值执行想要的命令,如上 if[ $? -eq 3 ];then
echo "行数过多,放弃读取"
else
echo 'getline执行完毕'
fi
二、函数与变量的作用范围。
1、函数的作用范围
函数仅在定义的shell环境中有效,Bash执行函数时,并不会另外再开启一个子shell。
如果要传递函数给shell环境使用,可以用内置命令export -f函数名称,这样此函数就变成了环境变量的一部分(函数型),可供子shell的script调用。
2、变量的作用范围
如果没有特别的设定变量的属性,那么在Script中自定义的变量称为全局变量(对此脚本而言)。作用范围在整个Script文件中皆有效。
#!/bin/bash
getline ()
{
local i=0 #这就定义了变量i只在函数getline中有效,变量i和函数外其它叫i的变量完全不一样。
while read line
do
....
三、位置参数
1、命令行的位置参数
$0 表示脚本名 $1 表示第一个参数 $2表示第2给参数 $(10)表示第10个参数
$* 代表所有的位置参数,看为一个字符串。1.sh a x y则$*为"a x y"
$@ 代表所有以空白隔开的参数,各位置串行。 1.ah a x y则$@为"a"、"x"、"y"
$# 位置参数的个数,1.ah a x y则$#的值为3
#!/bin/bash
if [ $# -ne 2 ];then 必须键入2个参数,否则错误退出
echo "使用方法:./$0 参数1 参数2"
exit 1
fi
2、移动位置参数
Bash的内置命令shift可以往前移动位置参数的值,语法如下:
shift n
n为正整数,代表往前移动的次数。n可以省略不写代表移动一次。执行 shift n,$(n+1)的值会放入$1
以执行shift命令来说(不指定次数),$2的值放入$1,$3的值放入$2,$4的值放入$3,,,如果一直执行shift(次数>=n),会把所有的位置参数清空
shift 一次清除1个(从$1开始) ,shift 2 一次清除2个
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/bin/bash echo "\$@的初始值为$@"
while shift
do [ -n "$1" ] && echo "shift 1次,\$@的变化:$@"
done 执行结果: [root@centos tmp] # bash 1.sh a b c d e
$@的初始值为a b c d e shift 1次,$@的变化:b c d e
shift 1次,$@的变化:c d e
shift 1次,$@的变化:d e
shift 1次,$@的变化:e
|
3、指定位置参数的值
指定位置参数的值称为重置(reset),用Bash命令set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/bash declare -i i=0
set 10 20 30 40 50
for p in $@
do
((i++))
echo " 第 $i 个位置参数 $$i = $p" #$$目前bash shell的进程编号
done [root@centos tmp] # bash 2.sh
第 1 个位置参数 3547i = 10
第 2 个位置参数 3547i = 20
第 3 个位置参数 3547i = 30
第 4 个位置参数 3547i = 40
第 5 个位置参数 3547i = 50
|
一旦用set重置位置参数,其原有的值就会消失,改以新值取代。(无论输入几个参数,set设置几个就是几个)
如果要一次重置所有参数,使其值为空,可执行 set --
4、取用命令行的选项和参数
在设计脚本的时候,往往需要由命令行中取得用户提供的选项和参数,根据不同的选项,脚本有不同的处理方式和执行结果。选项的使用方式可以
是单一选项,也可以在选项后方加上准备作用的参数,而且,选项出现的次序并没有严格的要求。
如以下例子:
./script -u jacken -a -h
或改用以下形式
./script -a -u jacken -h
如果要想取得这些选项和参数,使用前述的位置参数也是可以的,不过拿到位置参数后,必须再做许多条件判断才行,因为选项可能以不同的次序
出现在命令行不同的位置,情况十分复杂。解决这样的问题,可改用Bash提供的内置命令getopts。
getopts语法如下:
getopts 选项行 选项变量
其中选项行,是由各选项的单一字符组成,如前述例子中用来3个选项,可组合成“u:ah”
如果某一个选项字符后方,接上":" 则表示该选项需要提供一个参数,如这里的u后面有":"
如果执行脚本的时候,选项u后方没有提供额外的参数,那么Bash就会显示“option requires an argument --u”的错误信息。
如果不想出现这种错误信息,可在选项行最前面加上":" 如 ":u:ah" 像这样子,u后边没有参数也不会报错了。
至于选项变量的作用是:
getopts由命令行取得选项,把它放入选项变量中,如果该选项需要额外的参数,参数值会放入OPTARG这个变量中。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
[root@Shell ~] # ./opt.sh -a
提供了选项a [root@Shell ~] # ./opt.sh -h
提供了选项h [root@Shell ~] # ./opt.sh -a -h
提供了选项a 提供了选项h [root@Shell ~] # ./opt.sh -u
. /opt .sh: option requires an argument -- u
[root@Shell ~] # ./opt.sh -u hello
提供了选项-u和参数:hello [root@Shell ~] # cat opt.sh
#!/bin/bash # while getopts u:ah opt
do case $opt in
u)
echo "提供了选项-u和参数:$OPTARG" ;;
a)
echo "提供了选项a" ;;
h)
echo "提供了选项h" ;;
*)
;;
esac
done [root@Shell ~] #
|
四、建立函数库
如果某些函数经常出现在设计的script中,可以考虑把这些函数抽出来,集中存成一个文件,但这个文件称为函数库。
在命名函数时,函数名称第一个字符使用_(下划线),通常这就代表系统用的函数或变量名称。
在/tmp下建立函数库mylib1.sh
_getip()
{
local tmp r ip #函数内部使用的变量设为私有
[ -z "$1" ] && return #如果位置参数$1为空,直接退出
shuzu=() #建立数组变量shuzu,作为传回ip字符串用,初始值设为空数组
tmp=$(ifconfig $1 | grep 'inet addr')
r=${tmp/inet addr:/}
ip=${r/Bcast*/}
shuzu=($ip) #将找到的ip设为第一个数组元素,作为函数处理结果的传回值
}
调用函数数据库的语法,. /路径/函数数据库 .也用source来表示
#!/bin/bash
MYLIB_DIR="/tmp" #设置函数库默认路径
if [ ! -d "MYLIB_DIR" ];then
MYLIB_DIR="." #如果默认路径不存在就设为当前目录
fi
. $MYLIB_DIR/mylib1.sh #调用函数库mylib1.sh
_getip eth0 #执行_getip传入的参数是网络接口的名称eth0
ip=${shuzu[0]} #取出代表函数执行结果的数组变量shuzu的第一个元素,设值给变量ip
if [ -n "$ip" ];then #判断$ip是否为空,-z 为空 -n不为空
echo "主机ip是:$ip"
else
echo "找不到IP"
fi
本文转自Jacken_yang 51CTO博客,原文链接:http://blog.51cto.com/linuxnote/1641215,如需转载请自行联系原作者