2011-01-07 79 views
9

据我所知,有两种方法可以在bash函数中创建局部变量:创建一个子shell或将每个变量声明为本地变量。bash中的局部变量:local vs subshel​​l

例如:

# using local 
function foo 
{ 
    local count 
    for count in $(seq 10) 
    do 
    echo $count 
    done 
} 

# using subshell 
function foo 
{ 
    (
    for count in $(seq 10) 
    do 
     echo $count 
    done 
) 
} 

Obvisously使用子shell是简单的写,因为你不必在意声明局部变量的所有版本(更不用提(环境)由诸如getopts之类的工具创建/导出的变量)。但我可以想象创建一个子shell有一个开销。

那么更好的方法是什么?有什么优点/缺点?

+0

,超过1000次测试运行`time`命令,查看在开销之外,我认为这是不存在的。 – Anders 2011-01-07 13:05:39

回答

9

创建一个子shell涉及到一个fork(),所以它肯定会有本地变量的开销。虽然子弹的价格便宜,但当你需要一个—他们不是免费的时候,你不用担心他们的成本。

如果您的脚本将被大量使用并且性能真的很重要(因此您将有数百个用户同时运行它,每天多次运行),那么您可能会担心子shell。 OTOH,如果你每月运行一次,剧本整体运行时间不超过10秒,那么你可能不会。

但是,为了清晰起见,明确说明并声明变量—要好得多,因为有人出现并说“这个子shell显然不需要”(和它真的不是;我想要从你的函数中删除子shell)。

看看Perl脚本的演变。他们开始作为一个免费的变量随需而变。他们逐渐变得更加严谨,现在正常的风格是预先声明所有变量。在某种程度上,shell遵循类似的路径—,但不像Perl那样严格。 Awk也是一个有趣的案例研究;它的函数使用全局变量,除非它们是函数的参数,这导致函数被写入3个有效参数(比如说)和5个非有效参数来有效地定义局部变量。它有点古怪,虽然它“有效”。

0

现在,确保所有函数始终将所有变量声明为本地,这是相当困难的。

我觉得这是很容易出错的,喜欢总是使用子shell-功能:

f() (
echo "we are a subshell" 
) 

不需要声明局部变量 - 也没有办法去改变全局变量。我认为这是好事!

一个额外的后果是,你总是需要检查这些功能的返回/退出代码,并采取相应的行动! 这是因为你不能从一个子shell函数中退出你的脚本!

f() (
    echo "Trying to exit" 
    exit 1 
) 

f 
echo "Did not exit" 

这不会退出您的脚本。 你需要做这样说:“但是我能想象,创造一个子shell有架空”

f() (
    echo "Trying to exit" 
    exit 1 
) 

f || exit $? 
echo "Did not exit" 

这将退出