在while循环中丢失环境

Dav*_*ins 3 bash

一个有趣的小bash预告片,我喜欢这个解释.

我将拥有的两个循环结构是相同的,显然不是.似乎在进行while循环时管道与重定向有一些区别.

输入文件

鉴于values.txt使用此内容调用此示例文件:

1
2
3
4
5
6
Run Code Online (Sandbox Code Playgroud)

管道到了

$ value=0; cat values.txt | while read var; do value=`expr $value + $var`; done
$ echo $value
0
Run Code Online (Sandbox Code Playgroud)

重定向

$ value=0; while read var; do value=`expr $value + $var`; done < values.txt
$ echo $value
21
Run Code Online (Sandbox Code Playgroud)

简而言之,清楚地在第一个版本中,while循环的每次迭代都有效地执行,()并且在第二个循环中每次迭代迭代为{}

问题不在于()和之间的区别{}.我的问题是导致while循环行为的这种差异的原因是什么?

是否存在逻辑上的原因,他们应该采取不同的行为,或者只是因为兼容性原因而无法在早期做出错误的选择?是否有可能管道while并获得{}行为?

sta*_*ise 7

这是一个已知问题,这里有很好的解释:http: //mywiki.wooledge.org/BashFAQ/024

引用最具说明性的部分:

在这种情况下,不同的壳表现出不同的行

  • BourneShell在输入或输出任何东西(循环,大小写等)时创建子shell,但是通过使用管道或重定向操作符('<','>')重定向简单命令.
  • 只有当循环是管道的一部分时,BASH才会创建一个新进程.
  • 只有当循环是管道的一部分时,KornShell才会创建它,但如果循环是它的最后一部分,则不会创建它.
  • POSIX指定了bash行为,但作为扩展允许管道的任何或所有部分在没有子shell的情况下运行(因此也允许KornShell行为).

至于最后一个问题:是的,它可能在某些shell中,并且只有当你有bash> = 4.2时才在bash中,并且在你的代码之前有禁用作业控制并使用以下代码启用lastpipe选项: set +m; shopt -s lastpipe