shell script 作为一种结构化的编程语言,允许在 script 中定义和使用函数。函数是将一组命令集或者语句形成一个可复用的代码块。
1. 函数定义
shell 函数和其他语言的函数一样,都需要先定义才能使用。
语法格式如下:
function_name ()
{
...
}
或者
function_name () {
...
}
或者
function function_name [()]
{
...
}
或者
function function_name [()] {
...
}
1 function_name 是函数名;花括号之间的内容是函数体(命令或者语句的集合)。
2 命令 function 是可选的。如果 function 存在,则后面的圆括号是可选的;如果省略 function,则后面的圆括号不能省略。
3 左花括号也可以写在和函数名的同一行。
2. 函数调用
shell 函数调用的方式和 shell 命令是一样的,可以把函数当作命令来使用。
语法格式如下:
function_name [arguments ...]
1 函数和参数之间、参数和参数之间使用空格分隔。
2 函数和命令在使用上基本相同,同样都可以使用 shell 的命令替换功能($()、``)。
示例 1
test.sh
ERROR_CODE=255
max_value ()
{
if [ $# != 2 ]; then
echo invalid argument
return $ERROR_CODE
fi
echo max number is $(($1 > $2 ? $1 : $2))
}
max_value 23 12
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
max number is 23
malihou@ubuntu:~$
示例 2
test.sh
version()
{
echo "GNU bash, version 4.2.24(1)"
}
bash_version=`version`
echo $bash_version
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
GNU bash, version 4.2.24(1)
malihou@ubuntu:~$
3. 函数名
shell 函数的函数名保存在数组变量 FUNCNAME 中。这个变量只能使用在函数中,使用在其他地方将无效。
示例 3
test.sh
func3 ()
{
echo $FUNCNAME : ${FUNCNAME[@]}
}
func2 ()
{
func3
echo $FUNCNAME : ${FUNCNAME[@]}
}
func1 ()
{
func2
echo $FUNCNAME : ${FUNCNAME[@]}
}
func1
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
func3 : func3 func2 func1 main
func2 : func2 func1 main
func1 : func1 main
malihou@ubuntu:~$
4. 函数参数
1 shell 允许在调用函数的时候使用任意个参数,函数以位置来引用传递过来的参数。因此参数在函数内部会成为位置参数,其使用方法和 script 中相同。
2 shell 会保存调用函数前的位置参数,以便在函数内部重新给位置参数赋值。在函数调用完成后,位置参数会还原回函数调用前的值。传递给函数的参数和传递给 script 的命令行参数不会被混淆。
3 位置参数可以使用在 script 和函数内部。
4 和其它语言不同的是,shell 将传递给函数的参数都解释为字符串,在这之前会对参数进行 ~ 展开、参数和变量展开、算术展开、命令替代操作。
示例 4
test.sh
num1=12
num2=23
num3=34
test_positonal_parameter ()
{
echo \$#=$# \$@="$@"
}
echo \$#=$# \$1=$1 \$2=$2
test_positonal_parameter $num1 $num2 $num3 45
echo \$#=$# \$1=$1 \$2=$2
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh 1 2
$#=2 $1=1 $2=2
$#=4 $@=12 23 34 45
$#=2 $1=1 $2=2
malihou@ubuntu:~$
5. 函数局部变量
1 在函数内部定义的变量在默认情况下都是全局变量(没有使用命令 local 声明),这些全局的变量在函数调用之后才可以在函数外部使用。
2 如果变量在使用命令 local 声明后,就成为局部变量,其只能在函数内部及其子函数内被使用。
3 在函数调用之后,所有在函数内定义且没有使用命令 local 声明的变量都可以在函数外部可见。
示例 5
test.sh
test_variable ()
{
var1=global
local var2=local
echo var1=$var1 var2=$var2
}
echo var1=$var1 var2=$var2
test_variable
echo var1=$var1 var2=$var2
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
var1= var2=
var1=global var2=local
var1=global var2=
malihou@ubuntu:~$
局部变量可以递归。因此在实现函数递归调用时,必须使用局部变量。但是太多层的递归会消耗大量的内存,因此递归调用需谨慎使用。
使用函数递归输出杨辉三角(pascal's triangle)。
示例 6
test.sh
if [ $# -eq 0 ]
then
echo invalid argument
exit
fi
recursive ()
{
local i=$1
local j=$2
local m
local n
if [ $j -eq 1 ] || [ $j -eq $i ]
then
return 1
fi
recursive $((i-1)) $((j-1))
m=$?
recursive $((i-1)) $((j))
n=$?
return $((m + n))
}
for i in `eval echo {1..$1}`
do
for j in `eval echo {1..$i}`
do
recursive $((i)) $((j))
result=$?
if [ $j -eq $i ]
then
echo "$result"
else
echo -n "$result "
fi
done
done
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh 6
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
malihou@ubuntu:~$
6. 函数返回值
1 shell 函数是有返回值的。命令 return 可选的带一个整数参数(不带参数的 return 等同于 return $?),这个整数值会返回给调用此函数的 script。同时这个整数值会赋给变量 $?。
2 如果在函数中不使用 return 返回或者使用不带参数的 return,则将返回函数最后一条语句的退出状态的值(exit status = $?)。
3 退出状态 $? 的值是有限制的,其值的范围为 0 <= $? <= 255。如果超出这个范围,shell 会对 $? 的值进行取模运算($? % 256)。
4 命令 return 只能使用在 shell 函数中,不能使用在其他地方。
示例 7
test.sh
test_return ()
{
return $1
}
test_return 128
echo \$?=$?
test_return 255
echo \$?=$?
test_return 258
echo \$?=$?
执行结果如下:
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
$?=128
$?=255
$?=2
malihou@ubuntu:~$
如果想在函数中返回一个大的整数值,则需要通过在函数中将返回值传递给一个全局变量来实现。或者是让函数将返回值输出到标准输出,然后再通过命令替代的方式捕获这个返回值。
示例 8
test.sh
return_value=0
if [ $# -lt 4 ]
then
echo invalid argument
exit
fi
max_value1 ()
{
return_value=$(($1 > $2 ? $1 : $2))
}
max_value2 ()
{
echo $(($1 > $2 ? $1 : $2))
}
max_value1 $1 $2
echo max value is $return_value
echo max value is `max_value2 $3 $4`
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh 1000 1234 2000 2234
max value is 1234
max value is 2234
malihou@ubuntu:~$
7. 创建函数文件
和 c 语言的库函数一样,在 shell 中可以把一些经常使用的函数放在一起,并保存在函数文件中。当函数文件加载到 shell 后,就可以在命令行或者 script 中调用函数文件中的函数。
1 函数文件的文件名可以任意选取。
2 使用命令 set 查看所有定义的变量和函数。
3 使用命令 unset 删除变量和函数。
8. 加载函数文件
加载函数文件时,需要使用命令 source file 和 . file 的方式。
示例 9
shell_function.sh
echo "Usage : compare two number"
max_value ()
{
return $(($1 > $2 ? $1 : $2))
}
加载函数文件,执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ source shell_function.sh
Usage : compare two number
malihou@ubuntu:~$
将函数加载到 shell 后,执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ max_value 23 45
malihou@ubuntu:~$
malihou@ubuntu:~$ echo $?
45
malihou@ubuntu:~$
如果需要在其他 script 中使用函数文件,则首先需要在 script 的开头使用 source file 和 . file 将函数文件加载到当前 script 中,才可以使用这些函数。
示例 10
test.sh
source shell_function.sh
max_value 123 23
echo the max value is : $?
执行结果如下
malihou@ubuntu:~$
malihou@ubuntu:~$ ./test.sh
Usage : compare two number
the max value is : 123
malihou@ubuntu:~$