为什么在bash中终止循环后变量值会丢失?

时间:2014-10-01 14:43:43

标签: bash

我有一个非常简单的bash脚本来计算文件每行出现的数字总和(我知道有更好的方法可以做到这一点,但我实际上需要这个总和作为辅助信息,脚本应该是某种东西更多以后)。脚本如下:

TOTAL=0;
cat $DATAFILE | while read LINE; 
do
      COUNT=`echo $LINE| awk '{print $2;}'`;
      TOTAL=$((TOTAL+COUNT));
done
echo "Total = $TOTAL";

但是,我总是得到输出“Total = 0”。令人惊讶的是,如果我在while循环中移动最后一行,我会得到正确的结果。例如,如果输入文件包含

A 5
B 3
C 6

我得到了输出

Total = 5
Total = 8
Total = 14

但是当前版本总是输出0.似乎分配给变量TOTAL的值在某种程度上会丢失。

任何人都可以帮我解决这个问题吗?

提前致谢

1 个答案:

答案 0 :(得分:5)

这是BashFAQ #24。幸运的是,由于不必要地使用cat,你只能在这里点击它 - 你没有充分的理由让管道在使用中。


管道的右侧(与其余内容一样,由瞬态子壳组成)在管道完成时退出,除非您shopt -s lastpipe处于活动状态。

相反,要么添加以下行:

shopt -s lastpipe

或重构你的循环:

while read LINE; 
do
      COUNT=`echo $LINE| awk '{print $2;}'`;
      TOTAL=$((TOTAL+COUNT));
done <"$DATAFILE"

...或者,如果真的需要从另一个进程管道,请使用进程替换:

while read LINE; 
do
      COUNT=`echo $LINE| awk '{print $2;}'`;
      TOTAL=$((TOTAL+COUNT));
done < <(cat "$DATAFILE")

顺便说一句,如果你的shebang是#!/bin/bash而不是#!/bin/sh,那么写得更好如下:

total=0
while read -r _ count do; 
  (( total += count ))
done <"$DATAFILE"

read可以在IFS本身的字符上拆分行 - 您不需要使用awk

按照惯例,变量名称应全部为小写,除非它们代表环境变量或shell内置函数。