【shell实战之】在函数中使用变量

在函数中使用变量时,需要注意它们的定义方式和处理方式。这是 shell 脚本中常见
错误的根源。

向函数传递参数

函数可以使用标准的位置变量来表示在命令行中传给函数的任何参数。例如,函数名保存在
$0 变量中,函数参数依次保存在$1$2 等变量中。也可以用特殊变量$#来确定传给函数的参数
数量。
在脚本中调用函数时,必须将参数和函数名放在同一行,就像下面这样:
func1 $value1 10 
# 函数可以用位置变量来获取参数值。
#!/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
addem 函数首先会检查脚本传给它的参数数目。如果没有参数或者参数多
于两个,那么 addem 会返回-1。如果只有一个参数,那么 addem 会将参数与自身相加。如果有
两个参数,则 addem 会将二者相加。

错误调用命令行参数方法

由于函数使用位置变量访问函数参数,因此无法直接获取脚本的命令行参数。下面的例子无
法成功运行:
$ cat badtest1 
#!/bin/bash 
# trying to access script parameters inside a function 
function badfunc1 { 
 echo $[ $1 * $2 ] 
} 
if [ $# -eq 2 ] 
then 
 value=$(badfunc1) 
 echo "The result is $value" 
else 
 echo "Usage: badtest1 a b" 
fi 
$ 
$ ./badtest1 
Usage: badtest1 a b 
$ ./badtest1 10 15 
./badtest1: * : syntax error: operand expected (error token is "* 
") 
The result is 
$ 
尽管函数使用了$1 变量和$2 变量,但它们和脚本主体中的$1 变量和$2 变量不是一回事。

正确调用命令行参数方法

要在函数中使用脚本的命令行参数,必须在调用函数时手动将其传入:
$ cat test7 
#!/bin/bash 
# trying to access script parameters inside a function 
function func7 { 
 echo $[ $1 * $2 ] 
} 
if [ $# -eq 2 ] 
then 
 value=$(func7 $1 $2) 
 echo "The result is $value" 
else 
 echo "Usage: badtest1 a b" 
 fi 
$ 
$ ./test7 
Usage: badtest1 a b 
$ ./test7 10 15 
The result is 150 
$ 
在将$1 变量和$2 变量传给函数后,它们就能跟其他变量一样,可供函数使用了。

在函数中处理变量

给 shell 脚本程序员带来麻烦的情况之一就是变量的作用域。作用域是变量的有效区域。在
函数中定义的变量与普通变量的作用域不同。也就是说,对脚本的其他部分而言,在函数中定义
的变量是无效的。
函数有两种类型的变量。
 全局变量
 局部变量

全局变量

全局变量是在 shell 脚本内任何地方都有效的变量。如果在脚本的主体部分定义了一个全局
变量,那么就可以在函数内读取它的值。类似地,如果在函数内定义了一个全局变量,那么也可
以在脚本的主体部分读取它的值。
在默认情况下,在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正
常访问:
$ cat test8 
#!/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" 
$ 
$ ./test8 
Enter a value: 450 
The new value is: 900 
$ 
$value 变量在函数外定义并被赋值。当 dbl 函数被调用时,该变量及其值在函数中依然有
效。如果变量在函数内被赋予了新值,那么在脚本中引用该变量时,新值仍可用。
但这种情况其实很危险,尤其是想在不同的 shell 脚本中使用函数的时候,因为这要求你清
清楚楚地知道函数中具体使用了哪些变量,包括那些用来计算非返回值的变量。这里有个例子可
以说明事情是如何被搞砸的:
$ cat badtest2
#!/bin/bash
# demonstrating a bad use of variables
function func1 {
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
$
$ ./badtest2
The result is 22
temp is larger
$
由于函数中用到了$temp 变量,因此它的值在脚本中使用时受到了影响,产生了意想不到
的后果。有一种简单的方法可以解决函数中的这个问题,那就是使用局部变量。

局部变量

无须在函数中使用全局变量,任何在函数内部使用的变量都可以被声明为局部变量。为此,
只需在变量声明之前加上 local 关键字即可:
local temp
也可以在变量赋值语句中使用 local 关键字:
local temp=$[ $value + 5 ]
local 关键字保证了变量仅在该函数中有效。如果函数之外有同名变量,那么 shell 会保持
这两个变量的值互不干扰。这意味着你可以轻松地将函数变量和脚本变量分离开,只共享需要共
享的变量:
$ cat test9
#!/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 
$ 
$ ./test9 
The result is 22 
temp is smaller 
$ 
现在,当你在 func1 函数中使用$temp 变量时,该变量的值不会影响到脚本主体中赋给
$temp 变量的值。

函数递归

局部函数变量的一个特性是自成体系(self-containment)。除了获取函数参数,自成体系的
函数不需要使用任何外部资源。
这个特性使得函数可以递归地调用,也就是说函数可以调用自己来得到结果。递归函数通常
有一个最终可以迭代到的基准值。许多高级数学算法通过递归对复杂的方程进行逐级规约,直到
基准值。
递归算法的经典例子是计算阶乘。一个数的阶乘是该数之前的所有数乘以该数的值。

阶乘函数用其自身计算阶乘的值:
$ cat test13 
#!/bin/bash 
# using recursion 
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" 
$ 
$ ./test13 
Enter value: 5 
The factorial of 5 is: 120 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值