我的一个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上,这使得你的CNT
variables永远不会改变(只有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" )
长解释:
CNT
为值0; |
上启动 while read
; $CNT
variables被导出到值为0的SubShell; CNT
值增加到5; 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"