脚本函数基础
创建函数
在 bash shell 脚本中创建函数的语法有两种。第一种语法是使用关键字 function,随后跟上分配给该代码块的函数名:
shellfunction name { commands }
name 定义了该函数的唯一名称。脚本中的函数名不能重复。
commands 是组成函数的一个或多个 bash shell 命令。调用该函数时,bash shell 会依次执行函数内的命令,就像在普通脚本中一样。
第二种在 bash shell 脚本中创建函数的语法更接近其他编程语言中定义函数的方式:
shellname() { commands }
函数名后的空括号表明正在定义的是一个函数。这种语法的命名规则和第一种语法一样。
使用函数
shell#!/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"
函数定义不一定非要放在 shell 脚本的最开始部分,但是要注意这种情况。如果试图在函数被定义之前调用它,则会收到一条错误消息。
函数返回值
bash shell 把函数视为一个小型脚本,运行结束时会返回一个退出状态码,有 3 种方法能为函数生成退出状态码。
默认的退出状态码
在默认情况下,函数的退出状态码是函数中最后一个命令返回的退出状态码。函数执行结束后,可以使用标准变量$?来确定函数的退出状态码:
shell#!/bin/bash # testing the exit status of a function func1() { echo "trying to display a non-existent file" ls -l badfile } func2() { ls -l badfile echo "trying to display a non-existent file" } echo "testing the function: " func1 echo "The exit status is: $?" func2 echo "The exit status is: $?"
该函数的退出状态码是函数内部最后一条命令执行返回做的状态,上例中func1返回的状态是1(badfile不存在),func2返回的状态是0(最后一条命令执行成功)
使用return命令
bash shell 会使用 return 命令以特定的退出状态码退出函数。return 命令允许指定一个整数值作为函数的退出状态码,从而提供了一种简单的编程设定方式:
shell#!/bin/bash # using the return command in a function function dbl { read -p "Enter a value: " value echo "doubling the value" # 函数执行一结束就立刻读取返回值。 return $[ $value * 2 ] # 退出状态码必须介于 0~255 } dbl echo "The new value is $?"
使用函数输出
正如可以将命令的输出保存到 shell 变量中一样,也可以将函数的输出保存到 shell 变量中:
result=$(dbl)
shell#!/bin/bash # using the echo to return a value function dbl { read -p "Enter a value: " value echo $[ $value * 2 ] } result=$(dbl) # 注意,result获取的不是dbl执行的状态码 # 而是最后一行命令输出的内容echo $[ $value * 2 ] echo "The new value is $result"
新函数会用 echo 语句来显示计算结果。该脚本会获取 dbl 函数的输出,而不是查看退出状态码。
在函数中使用变量
向函数传递参数
函数可以使用标准的位置变量来表示在命令行中传给函数的任何参数。例如,函数名保存在$0 变量中,函数参数依次保存在$1、2 等变量中。也可以用特殊变量#来确定传给函数的参数数量。
在脚本中调用函数时,必须将参数和函数名放在同一行,就像下面这样:
func1 $value 10
shell#!/bin/bash # passing parameters to a function 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 number: " value=$(addem 10) echo $value echo -n "Now try adding no numbers: " value=$(addem) echo $value echo -n "Finally, try adding three numbers: " value=$(addem 10 15 20) echo $value
在函数中处理变量
全局变量是在 shell 脚本内任何地方都有效的变量。如果在脚本的主体部分定义了一个全局变量,那么就可以在函数内读取它的值。
在默认情况下,在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问:
shell#!/bin/bash # using a global variable to pass a value function dbl { value=$[ $value * 2 ] } read -p "Enter a value: " value dbl echo "The new value is: $value"
$value 变量在函数外定义并被赋值。当 dbl 函数被调用时,该变量及其值在函数中依然有效。如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值仍可用。
局部变量:无须在函数中使用全局变量,任何在函数内部使用的变量都可以被声明为局部变量。只需在变量声明之前加上 local 关键字即可:
local temp
也可以在变量赋值语句中使用 local 关键字:
local temp=$[ $value + 5 ]
local 关键字保证了变量仅在该函数中有效。如果函数之外有同名变量,那么 shell 会保持这两个变量的值互不干扰。
shell#!/bin/bash # demonstrating the local keyword function func1 { local temp=$[ $value + 5 ] result=$[ $temp * 2 ] } temp=4 value=6 func1 echo "The result is $result" if [ $temp -gt $value ] then echo "temp is larger" else echo "temp is smaller" fi
数组变量和函数
向脚本函数传递数组变量的方法:先将数组变量拆解成多个数组元素,然后将这些数组元素作为函数参数传递。最后在函数内部,将所有的参数重新组合成一个新的数组变量。
shell#!/bin/bash # array variable to function test function testit { local sum=0 local newarray newarray=(`echo "$@"`) echo "The new array value is: ${newarray[*]}" for value in ${newarray[*]} do sum=$[ $sum + $value ] done echo $sum } myarray=(1 2 3 4 5) echo "The original array is ${myarray[*]}" testit ${myarray[*]}
$myarray变量保存所有的数组元素,然后将其作为参数传递给函数。该函数随后根据参数重建数组变量。
函数向 shell 脚本返回数组变量:函数先用 echo 语句按正确顺序输出数组的各个元素,然后脚本再将数组元素重组成一个新的数组变量:
shell#!/bin/bash # returning an array value function arraydblr { local origarray local newarray local elements local i origarray=($(echo "$@")) newarray=($(echo "$@")) elements=$[ $# - 1 ] for (( i = 0; i <= $elements; i++ )) { newarray[$i]=$[ ${origarray[$i]} * 2 ] } echo ${newarray[*]} } myarray=(1 2 3 4 5) echo "The original array is: ${myarray[*]}" arg1=$(echo ${myarray[*]}) result=($(arraydblr $arg1)) echo "The new array is: ${result[*]}"
该脚本通过$arg1 变量将数组元素作为参数传给 arraydblr 函数。arraydblr 函数将传入的参数重组成新的数组变量,生成该数组变量的副本。然后对数据元素进行遍历,将每个元素的值翻倍,并将结果存入函数中的数组变量副本。
创建库
bash shell 允许创建函数库文件,然后在多个脚本中引用此库文件。
定义函数库文件 myfuncs.sh
shell# my script functions function addem { echo $[ $1 + $2 ] } function multem { echo $[ $1 * $2 ] } function divem { if [ $2 -ne 0 ] then echo $[ $1 / $2 ] else echo -1 fi }
在需要用到这些函数的脚本文件中包含 myfuncs 库文件
使用函数库的关键在于 source 命令。source 命令会在当前 shell 的上下文中执行命令,而不是创建新的 shell 并在其中执行命令。可以用 source 命令在脚本中运行库文件。这样脚本就可以使用库中的函数了。
source 命令有个别名,称作点号操作符,可以用"点"代替
shell#!/bin/bash # using a library file the wrong way # 引入函数库 # source ./myfuncs # 引入函数库 推荐写法 . ./mufuncs # 注意点后面的空格 result=$(addem 10 15) echo "The result is $result"