为什么这个For循环与Bash中的While循环不一样?

时间:2011-12-09 22:08:50

标签: bash variables loops

好的,所以我正在尝试解析一个在列中输出我需要的行的文件,而且我无法使这个while循环起作用,而且我真的很难过。

有趣的是,使用for循环执行几乎完全相同的操作可以正常工作。有人可以解释一下这里发生了什么吗?

此...

e=""
for f in 1 2 3
do 
    echo $f 
    e="$e.$f"
done
echo $e

输出:

1
2
3
.1.2.3

但是这......

e=""
echo "1
2
3" | while read f
do 
    echo $f 
    e="$e.$f"
done
echo $e

输出:

1
2
3

显然,当$f到达e="$e.$f"时,两个循环在{{1}}中都有1,2或3个,那么第二个循环不起作用的是什么?

4 个答案:

答案 0 :(得分:8)

我无法告诉你有多少次我不得不从某人的代码中删除这个错误。

管道基本上会生成分叉过程。 e在forked进程中设置,但是当它终止时(在wile循环结束时),父进程不知道e已经改变。简而言之,永远不要在涉及管道的命令中设置变量。管道完成后不会设置。更短......如果可以避免使用,请不要使用管道。

e=''
while read f
do
  echo $f
  e="$e.$f"
done << EOF
1
2
3
EOF
echo $e

答案 1 :(得分:3)

管道将在子shell中执行。所以在管道命令执行后,变量e没有改变。

答案 2 :(得分:3)

由于while read... done是管道的一部分,它就像其他二进制文件(称为子shell )一样获得自己的分叉过程映像。 (令人困惑的部分是它是用shell编写的,但是它不是作为当前shell进程的一部分执行的。)这就是为什么变量不会得到更新。

作为一种解决方法,你总是可以做这样的事情(使用bashisms):

while read line
do
    blablabla
done < <(echo "1 2 3")

在这里,您避免设置管道,因此while...done shell代码将作为当前脚本的一部分执行。

答案 3 :(得分:1)

我猜这是变量范围的差异。将echo语句传递给while语句时,全局e不在其范围内,因此它打印f并设置新变量e。当while循环退出时,全局e没有改变。因此,您的陈述echo $e不会打印任何内容。