在编写shell脚本时,你经常会发现在多个地方使用了同一段代码.如果只是一小段代码,一般也无关紧要但要在shell脚本中多次重写大块代码段就太累人了.bash shell提供的用户自定义函数功能可以解决这个问题。可以将shell脚本代码放进函数中封装起来,这样就能在脚本中的任何地方多次使用它了。
一.基本的脚本函数
在开始编写较复杂的shell脚本时,你会发现自己重复使用了部分能够执行特定任务的代码这些代码有时很简单,比如显示一条文本消息,或者从脚本用户那里获得一个答案;有时则会比较复杂,需要作为大型处理过程中的一部分被多次使用。
在后一类情况下,在脚本中一遍又一遍的编写同样的代码会很烦人。如果能只写一次,随后在脚本中科多次引用这部分代码就好了。
bash shell提供了这种功能。函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用。要在脚本中使用该代码块时,只要使用所起的函数名就行了(这个过程称为调用函数)。
1.创建函数
有两种格式可以用来在bash shell脚本中创建函数。第一种格式采用关键字function,后跟分配给该代码块的函数名。
function name {
commands
}
name属性定义了富裕函数的唯一名称。脚本中定义的每个函数都必须有一个唯一的名称。
commands是构成函数的一条或多条bash shell命令。在调用该函数时,bash bash会按明亮在函数中出现的顺序依次执行,就像在普通脚本中一样。
在bash shell脚本中定义函数的第二种格式更接近于其他编程语言中定义函数的方式。
name() {
commands
}
函数名后的空括号表明正在定义的是一个函数。这种格式的命名规则和之前定义shell脚本函数的格式一样。
2.使用函数
要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。
$ cat test1
#!/bin/bash
# using a function in a script
function func1 {
echo "This is an example of a function"
}
count=1
while [ $count -le 5 ]
do
func1
count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func1
echo "Now this is the end of the script"
$
$ ./test1
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is the end of the loop
This is an example of a function
Now this is the end of the script
$
每次引用函数名func1时,bash shell会找到func1函数的定义并执行你在那里定义的命令。
函数定义不一定非得是shell脚本中首先要做的事,但一定要小心。如果在函数被定义前使用函数,你会收到一条错误消息。
$ cat test2
#!/bin/bash
# using a function located in the middle of a script
count=1
echo "This line comes before the function definition"
function func1 {
echo "This is an example of a function"
}
while [ $count -le 5 ]
do
func1
count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func2
echo "Now this is the end of the script"
function func2 {
echo "This is an example of a function"
}
$
$ ./test2
This line comes before the function definition
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is the end of the loop
./test2: func2: command not found
Now this is the end of the script
$
第一个函数func1的定义出现在脚本中的几条语句之后,这当然没任何问题。当func1函数在脚本中被使用时,shell知道去哪里找它。
然而,脚本试图在func2函数被定义之前使用它。由于func2函数还没有定义,脚本运行函数调用处时,产生了一条错误消息。
你也必须注意函数名。记住,函数名必须是唯一的,否则也会有问题。如果你重定义了函数,新定义会覆盖原来函数的定义,这一切不会产生任何错误消息。
$ cat test3
#!/bin/bash
# testing using a duplicate function name
function func1 {
echo "This is the first definition of the function name"
}
func1
function func1 {
echo "This is a repeat of the same function name"
}
func1
echo "This is the end of the script"
$
$ ./test3
This is the first definition of the function name
This is a repeat of the same function name
This is the end of the script
$
func1函数最初的定义工作正常,但重新定义该函数后,后续的函数调用都会使用第二个定义。
二.返回值
bash shell会把函数当作一个小型脚本,运行结束时会返回一个退出状态码。有3种不同的方法来为函数生成退出状态码。
1.默认退出状态码
默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束后,可以用标准变量$?来确定函数的退出状态码。
$ cat test4
#!/bin/bash
# testing the exit status of a function
func1() {
echo "trying to display a non-existent file"
ls -l badfile
}
echo "testing the function: "
func1
echo "The exit status is: $?"
$
$ ./test4
testing the function:
trying to display a non-existent file
ls: badfile: No such file or directory
The exit status is: 1
$
函数的退出状态码是1,这是因为函数中的最后一条命令没有成功运行。但你无法知道函数中其他命令中是否成功运行。看下面的例子。
$ cat test4b
#!/bin/bash
# testing the exit status of a function
func1() {
ls -l badfile
echo "This was a test of a bad command"
}
echo "testing the function:"
func1
echo "The exit status is: $?"
$
$ ./test4b
testing the function:
ls: badfile: No such file or directory
This was a test of a bad command
The exit status is: 0
$
这次,由于函数最后一条语句echo运行成功,该函数的退出状态码就是0,尽管其中有一条命令并没有正常运行。使用函数的默认退出状态码是很危险的。幸运的是,有几种办法可以解决这个问题。
2.使用return命令
bash shell使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来编程设定函数退出状态码。
$ cat test5
#!/bin/bash
# using the return command in a function
function dbl {
read -p "Enter a value: " value
echo "doubling the value"
return $[ $value * 2 ]
}
dbl
echo "The new value is $?"
$
dbl函数会将$value变量中用户输入的值翻倍,然后用return命令返回结果。脚本用$?变量显示了该值。
但当用这种方法从函数中返回值时,要小心了。记住下面两条技巧来避免问题:
记住,函数一结束就取返回值;
记住,退出状态码必须是0~255。
如果在用$?变量提取函数返回值之前执行了其他命令,函数的返回值就会丢失。记住,$?变量会返回执行的最后一条命令的退出状态码。
第二个问题界定了返回值的取值范围。由于退出状态码必须小于256,函数的结果必须生成一个小于256的整数值。任何大于256的值都会产生一个错误值。
$ ./test5
Enter a value: 200
doubling the value
The new value is 1
$
要返回较大的整数值或者字符串值的话,你就不能用这种返回值的方法了。我们在下一节中将会介绍另一种方法。
3.使用函数输出
正如可以将命令的输出保存到shell变量中一样,你也可以对函数的输出采用同样的处理办法。可以用这种技术来获得任何类型的函数输出,并将其保存到变量中:
result='dbl'
这个命令会将dbl函数的输出赋给$result变量。下面是在脚本中使用这种方法的例子。
$ cat test5b
#!/bin/bash
# using the echo to return a value
function dbl {
read -p "Enter a value: " value
echo $[ $value * 2 ]
}
result=$(dbl)
echo "The new value is $result"
$
$ ./test5b
Enter a value: 200
The new value is 400
$
$ ./test5b
Enter a value: 1000
The new value is 2000
$