我的一个 shell 脚本有问题。问了几个同事,他们都只是摇头(挠了挠头),所以我来这里是为了回答。
根据我的理解,下面的 shell 脚本应该打印“Count is 5”作为最后一行。除了它没有。它打印“计数为 0”。如果将“while read”替换为任何其他类型的循环,它就可以正常工作。这是脚本:
echo "1">input.data 回声“2”>>输入.数据 回声“3”>>输入.数据 echo "4">>input.data 回声“5”>>input.data 碳纳米管=0 cat input.data | 阅读时; 做 让 CNT++; echo "计数到 $CNT" 完毕 echo "计数是 $CNT"
为什么会发生这种情况,我该如何预防?我已经在 Debian Lenny 和 Squeeze 中尝试过这个,结果相同(即 bash 3.2.39 和 bash 4.1.5。我完全承认不是一个 shell 脚本向导,所以任何指针都将不胜感激。
cor*_*ump 40
这是一种“常见”错误。管道创建子外壳,因此while read它在与脚本不同的外壳上运行,这使您的CNT变量永远不会改变(只有管道子外壳内的变量)。
将最后一个echo与子shell分组while以修复它(还有许多其他方法可以修复它,这是一种。Iain 和 Ignacio 的答案还有其他方法。)
CNT=0
cat input.data | ( while read
do
let CNT++;
echo "Counting to $CNT"
done
echo "Count is $CNT" )
Run Code Online (Sandbox Code Playgroud)
长解释:
CNT在脚本中声明值为 0;|到while read;$CNT变量以值 0 导出到 SubShell;CNT值增加到 5;echo的原始CNT值是 0。Ign*_*ams 31
请参阅参数@ Bash FAQ 条目 #24:“我在循环中设置变量。为什么在循环终止后它们突然消失?或者,为什么我不能通过管道读取数据?” (最近存档在这里)。
总结:这仅从 bash 4.2 及更高版本支持。如果您使用 bash,则需要使用不同的方式,例如命令替换而不是管道。
use*_*517 11
这有效
CNT=0
while read ;
do
let CNT++;
echo "Counting to $CNT"
done <input.data
echo "Count is $CNT"
Run Code Online (Sandbox Code Playgroud)
尝试在子 shell 中传递数据,就像它是 while 循环之前的文件一样。这类似于 lain 的解决方案,但假设您不想要一些间歇性文件:
total=0
while read var
do
echo "variable: $var"
((total+=var))
done < <(echo 45) #output from a command, script, or function
echo "total: $total"
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是简单地shopt -s lastpipe在 while 循环之前添加。
我说,如果出现麻烦,因为 while 位于管道的最后一段,并且在 Bash 中,管道中的所有命令都在彼此隔离的单独进程的子 shell 中执行,然后使用将执行最后lastpipe一个前台管道中的命令。
例如:
CNT=0
shopt -s lastpipe
cat input.data | while read ;
...
Run Code Online (Sandbox Code Playgroud)
几乎一切都保持不变。
| 归档时间: |
|
| 查看次数: |
109200 次 |
| 最近记录: |