在 Bash 中增加一个全局变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4257432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Increment a global variable in Bash
提问by zserge
Here's a shell script:
这是一个shell脚本:
globvar=0
function myfunc {
let globvar=globvar+1
echo "myfunc: $globvar"
}
myfunc
echo "something" | myfunc
echo "Global: $globvar"
When called, it prints out the following:
调用时,它会打印出以下内容:
$ 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
The question is: why this happens and what behavior is correct?
问题是:为什么会发生这种情况以及哪些行为是正确的?
P.S.I have a strange feeling that function behind the pipe is called in a forked shell... So, can there be a simple workaround?
PS我有一种奇怪的感觉,管道后面的函数在一个分叉的shell中被调用......那么,有没有一个简单的解决方法?
P.P.S.This function is a simple test wrapper. It runs test application and analyzes its output. Then it increments $PASSED or $FAILED variables. Finally, you get a number of passed/failed tests in global variables. The usage is like:
PPS这个函数是一个简单的测试包装器。它运行测试应用程序并分析其输出。然后它增加 $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"
采纳答案by Paused until further notice.
Korn shell gives the same results as zsh, by the way.
顺便说一下,Korn shell 给出的结果与 zsh 相同。
Please see BashFAQ/024. Pipes create subshells in Bash and variables are lost when subshells exit.
请参阅BashFAQ/024。管道在 Bash 中创建子外壳,当子外壳退出时变量会丢失。
Based on your example, I would restructure it something like this:
根据你的例子,我会像这样重构它:
globvar=0
function myfunc {
echo $(( + 1))
}
myfunc "$globvar"
globalvar=$(echo "something" | myfunc "$globalvar")
回答by mkb
Piping something into myfuncin shor bashcauses a new shell to spawn. You can confirm this by adding a long sleep in myfunc. While it's sleeping call ps and you'll see a subprocess. When the function returns, that sub shell exits without changing the value in the parent process.
将某些东西放入管道myfunc中sh或bash导致产生新的外壳。您可以通过在myfunc. 当它在睡眠时调用 ps ,你会看到一个子进程。当函数返回时,该子 shell 退出而不更改父进程中的值。
If you really need that value to be changed, you'll need to return a value from the function and check $PIPESTATUS after, I guess, like this:
如果你真的需要改变那个值,你需要从函数返回一个值,然后检查 $PIPESTATUS ,我猜,像这样:
globvar=0
function myfunc {
let globvar=globvar+1
echo "myfunc: $globvar"
return $globvar
}
myfunc
echo "something" | myfunc
globvar=${PIPESTATUS[1]}
echo "Global: $globvar"
回答by Jonathan Leffler
The problem is 'which end of a pipeline using built-ins is executed by the original process?'
问题是“原始进程执行使用内置函数的管道的哪一端?”
In zsh, it looks like the last command in the pipeline is executed by the main shell script when the command is a function or built-in.
在 zsh 中,当命令是函数或内置命令时,管道中的最后一个命令似乎由主 shell 脚本执行。
In Bash (and sh is likely to be a link to Bash if you're on Linux), then either both commands are run in a sub-shell or the first command is run by the main process and the others are run by sub-shells.
在 Bash 中(如果你在 Linux 上,sh 可能是 Bash 的链接),那么两个命令都在子 shell 中运行,或者第一个命令由主进程运行,其他命令由子进程运行贝壳。
Clearly, when the function is run in a sub-shell, it does not affect the variable in the parent shell (only the global in the sub-shell).
显然,当函数在子shell中运行时,它不会影响父shell中的变量(只影响子shell中的全局变量)。
Consider adding an extra test:
考虑添加一个额外的测试:
echo Something | { myfunc; echo $globvar; }
echo $globvar
回答by mb14
Use exportinstead of let, otherwise the variable is local
(use $(()) as well to do arithmetic operation)
使用export代替let,否则变量是局部变量(也使用 $(()) 进行算术运算)
export globvar=0
function myfunc {
export globvar=$((globvar+1))
echo "myfunc: $globvar"
}

