2012-10-10 88 views
1

我使用command | awk '{ print $1; }' | while read val ; do來循環顯示命令輸出。最近,我想要計算總和,我發現在bash一些奇怪的行爲:test.txt的爲什麼一個變量在一個循環內更改,在循環外部保持不變

內容的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" 

100 
200 
300 

內容從執行test.sh輸出

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

最終總和應該是600.我該如何解決這個問題?

回答

2

要展開什麼newfurniturey狀態,但在某種程度上,你可以用arbritary輸入指令,不只是cat使用它:

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 test.txt與任何命令,輸出您所需要的輸入。

+3

+1。我只是補充一點,關於這裏發生了什麼的文檔是在[**'bash'手冊頁**上](http://www.freebsd.org/cgi/man.cgi?query=bash&apropos = *&sektion = 0&manpath = FreeBSD + Ports&arch = default&format = html#EXPANSION)標題爲「[* Process Substitution *]」(http://www.tldp.org/LDP/abs/html/abs-guide.html#PROCESS -SUB)」。 – ghoti

2

原因是使用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" 

如果你實際上並不需要環(即 - 如果你不處理任何其他列/內容處理) ,你可以直接使用awk,它的值存儲到sum變量:

sum=`awk '{ sum += $1; } END { print sum }' test.txt`; 
+0

嗨,在我的情況下,它不是貓命令 – JMW

+0

OP希望用awk預處理輸入,爲此,您可以用'done < imp25

+0

@ imp25示例文件的內容只包含一列 - 所以'awk'{print $ 1}''是多餘的;然而,我更新的答案允許充分利用*而不需要循環(考慮到OP不需要循環內的任何額外處理)。 – newfurniturey

2

有沒有必要在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 
+0

+1。管道是一個強大的工具,不會被那些不瞭解它們的人使用。不過,Awk應該被所有人使用。 :) – ghoti

0

這種奇怪的行爲實際上是由基本的bash管道

造成引述Bash reference manual

管道中的每個命令在自己的子shell作爲執行的sum

思考你的while循環中的局部變量,這就是爲什麼sum出現while循環時不會被設置的原因。

其他人提出的解決方案將正常工作。

相關問題