【问题标题】:Increment a global variable in Bash在 Bash 中增加一个全局变量
【发布时间】:2011-05-14 12:48:31
【问题描述】:

这是一个 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"

【问题讨论】:

  • 好吧,在我看来 $globvar 不是局部变量,因为在没有管道的情况下调用 myfunc() 可以很好地增加全局变量 $globvar。问题是通过管道调用函数在 bash/sh 中不起作用。

标签: bash unix global increment


【解决方案1】:

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

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

根据您的示例,我将对其进行重组:

globvar=0

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

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

【讨论】:

  • 感谢您的链接!问题是如何传回两个变量:$PASSED 和 $FAILED。我知道,我可以查找 $?,如果它等于零 - 我自己增加 $PASSED,否则 - 增加 $FAILED。我只想在 myfunc() 之外编写尽可能少的代码。
  • @zserge:一种方法是:myfunc() { echo "two words"; }; read word1 word2 &lt;&lt;&lt; $(myfunc)array=($(myfunc))
【解决方案2】:

shbash 中将某些内容导入myfunc 会导致生成一个新的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"

【讨论】:

  • 酷。我以前不知道PIPESTATUS
  • 这种技术的唯一问题是您的返回值必须在 0-255 范围内。
【解决方案3】:

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

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

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

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

考虑添加一个额外的测试:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多