在shell中有一段代码需要重复使用时,就可以用函数来代替。
函数创建与使用
有两种格式可以用来在bash shell脚本中创建函数。第一种格式采用关键字function,后跟分配给该代码块的函数名:
function name { commands }
|
name属性定义了赋予函数的唯一名称。脚本中定义的每个函数都必须是唯一的名称。
bash shell脚本中定义函数的第二种格式跟在其他语言中定义函数很像:
函数名后的圆括号为空,表明正在定义的是一个函数。
用在脚本中使用函数,在行上指定函数名就行了,跟使用其他shell命令一样:
$ cat test10.sh #!/bin/bash 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 srcipt" $ $ ./test10.sh 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 srcipt
|
函数的返回值
bash shell会把函数当作小型脚本,运行结束时会返回一个退出状态码。有3中不同的方法来为函数生成退出状态码。
1. 默认退出状态码
默认情况下,函数的退出状态码是函数中最后一条命令返回的退出码。在函数执行结束后,你可以用标准的$?变量来决定函数的退出状态码:
$ cat test11.sh #!/bin/bash func1() { ls -l badfile echo "This was a test of a bad command" } echo "testing the function:" func1 echo "The exit status is: $?" $ $ ./test11.sh testing the function: ls: 无法访问badfile: 没有那个文件或目录 This was a test of a bad command The exit status is: 0 $
|
从上述代码可以看到,由于函数以成功运行的echo语句结尾,函数的退出状态码就是0,尽管函数中有一条命令没有运行成功。使用函数的默认退出状态码是很危险的。
2. 使用return命令
bash shell使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个整数值来定义函数的退出状态码:
$ cat test12.sh #!/bin/bash function db1 { read -p "Enter a value: " value echo "doubling the value" return $[ $value * 2 ] } db1 echo "The new value is $?" $ ./test12.sh Enter a value: 12 doubling the value The new value is 24 $
|
但当使用这种方法从函数中返回值时,要记住下面两点:
- 函数一结束就取返回值
- 退出状态码必须在0~255之间。
如果在用$?变量提取函数返回值之前执行了其他命令,函数的返回值就可能会丢失。
3. 使用函数输出
正如同可以将命令的输出保存在shell变量中一样,也可以将函数的输出保存到shell变量中。可以用这种技术来获得任何类型的函数输出,并将其保存到变量中:
$ cat test13.sh #!/bin/bash function db1 { read -p "Enter a value: " value echo $[ $value * 2 ] } result=`db1` echo "The new value is $result" $ ./test13.sh Enter a value: 200 The new value is 400 $
|
本示例演示了一个小技巧。你会注意到db1函数输出了两条消息。read命令输出了一条简短的消息来向用户询问输入值。bash shell脚本会聪明地不将它作为STDOUT输出的一部分,并且忽略掉它。如果你用echo语句生成这条消息来向用户查询,则shell命令会将其与输出值一起读进变量中。
通过这种方法,你还可以返回浮点值和字符串值。这让它非常适合返回函数值。
函数中使用变量
函数可以使用标准的参数环境变量来代表命令行上传给函数的参数。例如,函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1,$2等定义。也可以用特殊变量$#来判断传给函数的参数数目。
在脚本中指定函数时,必须将参数和函数放在同一行:
$ cat test14.sh #!/bin/bash function addem { if [ $# -eq 0 ] || [ $# -gt 2 ]; then echo -1 elif [ $# -eq 1 ]; then echo $[ $1 + $1 ] else echo $[ $1 + $2 ] fi } echo -n "Adding 10 and 15: " value=`addem 10 15` echo $value echo -n "Let's try adding just one numbers: " value=`addem 10` echo $value echo -n "Now let's try adding no numbers: " value=`addem` echo $value echo -n "Finally, let't try adding three numbers: " value=`addem 10 15 20` echo $value $ $ ./test14.sh Adding 10 and 15: 25 Let's try adding just one numbers: 20 Now let's try adding no numbers: -1 Finally, let't try adding three numbers: -1 $
|
函数中的全局变量与局部变量
全局变量是在shell脚本中任何地方都有效的变量。默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问。
不用在函数中使用全局变量,函数每部使用的任何变量都可以被声明成局部变量。要那么做时,只要在变量声明的前面加上local关键字就可以了。
下面是全局变量与局部变量的例子:
$ cat test15.sh #!/bin/bash function func1 { local temp=$[ $value + 5 ] temp=$[ $temp * 2 ] value=$[ $value + 5 ] } temp=4 value=6 echo "Before func1, temp is $temp, value is $value" func1 echo "After func1, temp is $temp, value is $value" $ $ ./test15.sh Before func1, temp is 4, value is 6 After func1, temp is 4, value is 11 $
|
从上面的例子可以看出,在函数内部声明的局部变量temp会覆盖全局变量temp,至于在声明了局部变量temp之后如何再引用全局变量变量temp,我目前还不知道。
函数与数组
向函数传递数组变量以及从函数返回数组稍微有点麻烦。首先是传递数组变量,你必须将该数组变量的值分解成单个值,然后将这些值作为函数参数使用,在函数内部,你可以将所有的参数重组到新的数组变量中;从函数里向shell脚本传回数组变量也用类似的方式。函数用echo语句来正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组中变量中:
$ cat test16.sh #!/bin/bash function testit { local newarray newarray=(`echo "$@"`) for (( i = 0; i < $#; i++ )) { newarray[$i]=$[ ${newarray[$i]} + 1 ] } echo ${newarray[*]} } myarray=(1 2 3 4 5) echo "The original array is ${myarray[*]}" arg1=`echo ${myarray[*]}` result=(`testit $arg1`) echo "The new array is: ${result[*]}" $ ./test16.sh The original array is 1 2 3 4 5 The new array is: 2 3 4 5 6 $
|
函数递归
bash shell的函数递归与其他语言类似,下面举一个阶乘递归的例子:
$ cat test17.sh #!/bin/bash function factorial { if [ $1 -eq 1 ]; then echo 1 else local temp=$[ $1 - 1 ] local result=`factorial $temp` echo $[ $result * $1 ] fi } read -p "Enter value: " value result=`factorial $value` echo "The factorial of $value is: $result" $ $ ./test17.sh Enter value: 4 The factorial of 4 is: 24
|