bash:variables在读循环结束时失去值

我的一个shell脚本有问题。 问了几个同事,但他们都只是摇头(经过一番搔抓),所以我来这里找答案。

根据我的理解,下面的shell脚本应该打印“Count is 5”作为最后一行。 除了没有。 它打印“计数为0”。 如果“while read”被其他任何types的循环代替,它就可以正常工作。 这是脚本:

 回声“1”> input.data
回声“2”>> input.data
回声“3”>> input.data
回声“4”>> input.data
回声“5”>> input.data

 CNT = 0 

 cat input.data | 同时阅读;
做
  让CNT ++;
  回声“计数到$ CNT”
 DONE 
回声“计数是$ CNT”

为什么会发生这种情况,我该如何预防呢? 我已经在Debian Lenny和Squeeze中尝试了这一点,相同的结果(即bash 3.2.39和bash 4.1.5。我完全承认不是一个shell脚本向导,所以任何指针将不胜感激。

请参阅参数@ Bash FAQ条目#24:“我在一个循环中设置variables,为什么在循环终止后突然消失?或者,为什么我不能通过pipe道读取数据? (最近在这里存档)。

这是一种“常见”的错误。 pipe道创buildSubShells,所以while read运行在与脚本不同的shell上,这使得你的CNTvariables永远不会改变(只有pipe道子shell里面的那个)。

将最后一个echo与子shell while分组, while修复它(还有很多其他的方法可以解决这个问题,Iain和Ignacio的答案有其他答案)。

 CNT=0 cat input.data | ( while read do let CNT++; echo "Counting to $CNT" done echo "Count is $CNT" ) 

长解释:

  1. 您在您的脚本上声明CNT为值0;
  2. SubShell在|上启动 while read ;
  3. 您的$CNTvariables被导出到值为0的SubShell;
  4. SubShell计数并将CNT值增加到5;
  5. SubShell结束,variables和值被销毁(他们不回到调用进程/脚本)。
  6. echo你原来的CNT值为0。

这工作

 CNT=0 while read ; do let CNT++; echo "Counting to $CNT" done <input.data echo "Count is $CNT" 

尝试在一个子shell中传递数据,就像在while循环之前的文件一样。 这与lain的解决scheme类似,但假设你不想要一些间歇性的文件:

 total=0 while read var do echo "variable: $var" ((total+=var)) done < <(echo 45) #output from a command, script, or function echo "total: $total"