Bash 为什么一个变量在一个循环内改变,而在循环外没有改变

Bash 为什么一个变量在一个循环内改变,而在循环外没有改变,bash,Bash,我在读取val时使用命令| awk'{print$1;}';执行循环执行命令输出。最近我想计算总和,我在bash中发现了一些奇怪的行为: test.txt的内容 100 200 300 测试内容。sh sum='0' cat test.txt | awk '{ print $1; }' | while read val ; do sum=`expr $sum + $val` echo "sum is now: $sum" done echo "FINAL SU

我在读取val时使用
命令| awk'{print$1;}';执行
循环执行命令输出。最近我想计算总和,我在
bash
中发现了一些奇怪的行为:

test.txt的内容

100
200
300
测试内容。sh

sum='0'
cat test.txt | awk '{ print $1; }' | while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done

echo "FINAL SUM: $sum"
sum is now: 100
sum is now: 300
sum is now: 600
FINAL SUM: 0
执行test.sh的输出

sum='0'
cat test.txt | awk '{ print $1; }' | while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done

echo "FINAL SUM: $sum"
sum is now: 100
sum is now: 300
sum is now: 600
FINAL SUM: 0

最后的总数应该是600。我能做些什么来修复此问题?

原因是使用了
cat
,这会产生另一个子shell。这意味着
sum
变量在第二个子shell中递增,然后在循环完成时超出范围(并返回到其先前的值
0

尝试更新循环以不使用
cat

sum='0'
while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done < test.txt

echo "FINAL SUM: $sum"
sum='0' 
while read val ; do
     sum=`expr $sum + $val`
     echo "sum is now: $sum" 
done < <(cat test.txt | awk '{ print $1 }')
echo "FINAL SUM: $sum"

原因是使用了
cat
,这会产生另一个子shell。这意味着
sum
变量在第二个子shell中递增,然后在循环完成时超出范围(并返回到其先前的值
0

尝试更新循环以不使用
cat

sum='0'
while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done < test.txt

echo "FINAL SUM: $sum"
sum='0' 
while read val ; do
     sum=`expr $sum + $val`
     echo "sum is now: $sum" 
done < <(cat test.txt | awk '{ print $1 }')
echo "FINAL SUM: $sum"

没有必要使用bash管道。您可以使用
awk

awk '{sum+= $1; printf "The sum is now: %s\n", sum } END { print "FINAL SUM:", sum }' file.txt
结果:

The sum is now: 100
The sum is now: 300
The sum is now: 600
FINAL SUM: 600

没有必要使用bash管道。您可以使用
awk

awk '{sum+= $1; printf "The sum is now: %s\n", sum } END { print "FINAL SUM:", sum }' file.txt
结果:

The sum is now: 100
The sum is now: 300
The sum is now: 600
FINAL SUM: 600

要扩展NewFurniture所述内容,但您可以将其与任意输入命令一起使用,而不仅仅是
cat

sum='0'
while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done < test.txt

echo "FINAL SUM: $sum"
sum='0' 
while read val ; do
     sum=`expr $sum + $val`
     echo "sum is now: $sum" 
done < <(cat test.txt | awk '{ print $1 }')
echo "FINAL SUM: $sum"
sum='0'
读val时;做
sum=`expr$sum+$val`
echo“总和现在是:$sum”

完成<以扩展NewFurniture的状态,但您可以将其与任意输入命令一起使用,而不仅仅是
cat

sum='0'
while read val ; do
        sum=`expr $sum + $val`
        echo "sum is now: $sum"
done < test.txt

echo "FINAL SUM: $sum"
sum='0' 
while read val ; do
     sum=`expr $sum + $val`
     echo "sum is now: $sum" 
done < <(cat test.txt | awk '{ print $1 }')
echo "FINAL SUM: $sum"
sum='0'
读val时;做
sum=`expr$sum+$val`
echo“总和现在是:$sum”

done<这种奇怪的行为实际上是由bash管道引起的

引用

管道中的每个命令都在其自己的子shell中执行

sum
视为while循环中的局部变量,这就是为什么退出while循环时,
sum
似乎没有设置的原因


其他人提出的解决方案可以正常工作。

这种奇怪的行为实际上是由bash管道引起的

引用

管道中的每个命令都在其自己的子shell中执行

sum
视为while循环中的局部变量,这就是为什么退出while循环时,
sum
似乎没有设置的原因


其他人提出的解决方案可以很好地工作。

OP希望使用awk预处理输入,为此,您可以使用
done<@imp25替换while循环的结束行。示例文件的内容仅包含一列-因此
awk'{print$1}'
是多余的;然而,我更新的答案允许在不需要循环的情况下充分利用它(考虑到OP在循环中不需要任何额外的处理)。我只是用cat来说明我的问题OP希望用awk预处理输入,要做到这一点,您可以用
done<@imp25替换while循环的结束行。示例文件的内容只包含一列-因此
awk'{print$1}'
是多余的;然而,我更新的答案允许在不需要循环的情况下充分利用它(考虑到OP在循环中不需要任何额外的处理)。我只是用猫来说明我的问题。管道是一个强大的工具,不了解管道的人不能使用。但是,每个人都应该使用Awk。:)+1.管道是一个强大的工具,不了解管道的人不能使用。但是,每个人都应该使用Awk。:)+1.我只想补充一点,关于这里发生的事情的文档在标题为“.+1”的章节中。我只想补充一点,关于这里发生的事情的文档在标题为“”的一节中。