在Bash中增加一个全局变量

时间:2010-11-23 15:09:20

标签: bash unix global increment

这是一个shell脚本:

globvar=0

function myfunc {
  let globvar=globvar+1
  echo "myfunc: $globvar"
}

myfunc
echo "something" | myfunc

echo "Global: $globvar"

调用时,会打印出以下内容:

$ sh zzz.sh
myfunc: 1
myfunc: 2
Global: 1
$ bash zzz.sh
myfunc: 1
myfunc: 2
Global: 1
$ zsh zzz.sh
myfunc: 1
myfunc: 2
Global: 2

问题是:为什么会发生这种情况以及哪种行为是正确的?

P.S。我有一种奇怪的感觉,管道后面的功能是在一个分叉的shell中调用的......所以,有没有一个简单的解决方法?

P.P.S。此函数是一个简单的测试包装器。它运行测试应用程序并分析其输出。然后它增加$ PASSED或$ FAILED变量。最后,您将在全局变量中获得许多通过/失败的测试。用法如下:

test-util << EOF | myfunc
input for test #1
EOF
test-util << EOF | myfunc
input for test #2
EOF
echo "Passed: $PASSED, failed: $FAILED"

4 个答案:

答案 0 :(得分:7)

顺便说一句,Korn shell给出了与zsh相同的结果。

请参阅BashFAQ/024。管道在Bash中创建子壳,当子壳退出时变量会丢失。

根据你的例子,我会重组它:

globvar=0

function myfunc {
    echo $(($1 + 1))
}

myfunc "$globvar"
globalvar=$(echo "something" | myfunc "$globalvar")

答案 1 :(得分:3)

myfuncsh中将某些内容放入bash会导致新的shell生成。您可以通过在myfunc中添加长睡眠来确认这一点。当它正在睡觉时调用ps,你会看到一个子进程。当函数返回时,该子shell退出而不更改父进程中的值。

如果你真的需要改变这个值,你需要从函数中返回一个值,然后检查$ PIPESTATUS,我猜,就像这样:

globvar=0

function myfunc {
  let globvar=globvar+1
  echo "myfunc: $globvar"
  return $globvar
}

myfunc
echo "something" | myfunc
globvar=${PIPESTATUS[1]}

echo "Global: $globvar"

答案 2 :(得分:0)

问题是'使用内置函数的管道的哪一端由原始进程执行?'

在zsh中,当命令是函数或内置函数时,看起来管道中的最后一个命令是由主shell脚本执行的。

在Bash中(如果你在Linux上,sh可能是Bash的链接),那么两个命令都在子shell中运行,或者第一个命令由主进程运行,其他命令运行通过子壳。

显然,当函数在子shell中运行时,它不会影响父shell中的变量(只有子shell中的全局变量)。

考虑添加额外的测试:

echo Something | { myfunc; echo $globvar; }
echo $globvar

答案 3 :(得分:-1)

使用export代替let,否则变量是本地的 (使用$(())也可以进行算术运算)

export globvar=0

function myfunc {
  export globvar=$((globvar+1))
  echo "myfunc: $globvar"
}