【问题标题】:Why variable values are lost after terminating the loop in bash? [duplicate]为什么在bash中终止循环后变量值会丢失? [复制]
【发布时间】:2014-11-26 10:49:16
【问题描述】:

我有一个非常简单的 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 的值似乎丢失了。

谁能帮我解决这个问题?

提前致谢

【问题讨论】:

标签: bash


【解决方案1】:

这是BashFAQ #24。幸运的是,您只是因为不必要地使用了cat 而在这里使用它——您根本没有充分的理由使用管道。


管道的右侧(与其内容的其余部分一样,由瞬态子shell组成)在管道完成时退出,除非您有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 内置函数。

【讨论】:

  • 这里的重要信息是管道的每个部分都在一个子shell中执行。这意味着while 循环在不同的 BASH 中执行,该 BASH 终止 -> 所有变量都随之终止。
猜你喜欢
  • 2018-04-07
  • 1970-01-01
  • 2012-04-18
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 2018-10-02
  • 2018-02-05
  • 1970-01-01
相关资源
最近更新 更多