在while循环中丢失环境 [英] Losing environment in while loop
问题描述
一个有趣的小玩笑预告片,我想解释一下.
A fun little bash teaser to which I'd love an explanation.
尽管我有两个循环构造是相同的,但显然不一样.似乎在进行 while
循环时,管道传输和重定向之间存在一些差异.
Two loop constructs I would have though are identical, clearly are not. Seems there's some difference in piping vs redirecting when doing a while
loop.
输入文件
给出一个名为 values.txt
的示例文件,其中包含以下内容:
Given this sample file called values.txt
with this content:
1
2
3
4
5
6
管道到
$ value=0; cat values.txt | while read var; do value=`expr $value + $var`; done
$ echo $value
0
重定向到while
$ value=0; while read var; do value=`expr $value + $var`; done < values.txt
$ echo $value
21
为简单起见,很明显,在第一个版本中, while
循环的每个迭代都有效地作为()
执行,而在第二个版本中,每个迭代均迭代为 {}
To be brief, clearly in the first version each iteration of the while
loop executes effectively as ()
and in the second each iteration iterates as {}
问题不是()
和 {}
之间的区别.我的问题是 while
循环在行为上有什么原因?
The question is not the difference between ()
and {}
. My question is what causes this difference in behavior for while
loops?
是出于逻辑原因,他们应该表现出不同的行为,还是只是出于兼容性原因而无法更改的早期错误选择?
Is there a logical reason they should behave differently or was it just a bad choice made early on that couldn't be changed for compatibility reasons? Is it ever possible to pipe to while
and get {}
behavior?
推荐答案
这是一个已知问题,并在此处进行了详细说明: http://mywiki.wooledge.org/BashFAQ/024
This is a known problem and is well explained here: http://mywiki.wooledge.org/BashFAQ/024
引用最具解释性的部分:
To quote the most explanatory part:
在这种情况下,不同的壳表现出不同的行为:
Different shells exhibit different behaviors in this situation:
- BourneShell 在输入或输出任何东西时创建一个子shell(循环,大小写等),但是通过以下方式重定向了简单的命令:使用管道或重定向运算符('<','>').
- BASH 仅在循环是管道的一部分时才创建新进程.
- KornShell 仅当循环是管道的一部分时才创建它,但如果循环是管道的一部分则不创建它是它的最后一部分.
- POSIX 指定bash行为,但扩展允许管道的任何或所有部分运行没有子外壳(因此也允许KornShell行为).
- BourneShell creates a subshell when the input or output of anything (loops, case etc..) but a simple command is redirected, either by using a pipeline or by a redirection operator ('<', '>').
- BASH creates a new process only if the loop is part of a pipeline.
- KornShell creates it only if the loop is part of a pipeline, but not if the loop is the last part of it.
- POSIX specifies the bash behaviour, but as an extension allows any or all of the parts of the pipeline to run without a subshell (thus permitting the KornShell behaviour, as well).
关于最后一个问题:是的,只有在bash> = 4.2的情况下,才能在某些shell中使用bash,并且在bash中也可以这样做,并且在代码之前先禁用工作控制并使用以下代码启用lastpipe选项:设置+ m;shopt -s lastpipe
As for the last question: yes, it is possible in certain shells, and in bash only if you have bash >=4.2, and preceed your code with disabling job control and enabling lastpipe option with the following code: set +m; shopt -s lastpipe
这篇关于在while循环中丢失环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!