4

一个有趣的小 bash 预告片,我很想解释一下。

我拥有的两个循环结构虽然是相同的,但显然不是。似乎在进行while循环时管道与重定向存在一些差异。

输入文件

给定使用此内容调用的示例文件values.txt

1
2
3
4
5
6

管道到 while

$ 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循环的每次迭代都有效地执行,()而在第二个版本中,每次迭代都以{}

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

是否有合乎逻辑的原因他们应该表现不同,或者这只是早期做出的错误选择,出于兼容性原因无法更改?是否有可能通过管道while获取{}行为?

4

1 回答 1

7

这是一个已知问题,并在此处进行了很好的解释:http: //mywiki.wooledge.org/BashFAQ/024

引用最具解释性的部分:

在这种情况下,不同的 shell 表现出不同的行为:

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

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

于 2012-09-16T07:39:33.637 回答