shell 编程 : 函数

Poem 2013-09-14

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:~$
 
 
 

来源: http://malihou2008.blog.163.com/blog/static/211820045201210462849297/

相关推荐