2011-04-18 34 views
4

考慮:離奇的bash範圍規則躲開我

t=0 ; for i in 1 2 3 4 5 6 7 8 9 10 ; do t=$((t+i)) ; done ; echo $t 

打印55

但是:

totsize=0 
find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du | \ 
while read size rest ; do 
    totsize=$((totsize+size)) 
    echo "$totsize" 
done 
echo "Sum: $totsize kb" 

打印 「總和:0 KB」 即使壽中期print語句打印合理和。

我知道我以前遇到過這個問題,但從來沒有理解它。有什麼區別?

+0

正確答案的硬幣折騰去久留。 sehe:+ 1代表<<()vs |,kurumi:+1代表find -printf。 Thx全部。 – Bittrance 2011-04-18 13:30:20

回答

6

這是因爲管道創建一個子shell這樣totsize是「本地」子shell裏面。你可以試試這個代替(bash)的

totsize=0 
while read size rest ; do 
    totsize=$((totsize+size)) 
    echo "$totsize" 
done < <(find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du) 
echo "Sum: $totsize kb" 

,而不是使用bash或者調用awk

$> find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du | awk '{s+=$1}END{print "total size: "s}' 

但你一定要使用剛剛du不帶任何選項,因爲大小非「準確「(使用du -b會更好)。如果您有GNU查找,您可以使用-printf

find /home/user -type f -mmin -4860 -a -mmin +3420 -printf "%s\n" | awk '{s+=$1}END{print "total size: "s" bytes"}' 
+0

+1用於暗示'-printf' – sehe 2011-04-18 12:34:04

8
totsize=0 

while read size rest ; do 
    totsize=$((totsize+size)) 
    echo "$totsize" 
done < <(find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du) 
echo "Sum: $totsize kb" 

防止子shell,因爲一個子shell會限制totsize


範圍支出幾句話:

do_something < <(subprocess) 
  • 將運行在主殼do_something(這是輸入重定向過程替代

subprocess | do_something 
  • 將運行在一個獨立的(子)外殼do_something(這是一個管子)
1

這是一個常見問題。管道的右側元素在子外殼中運行。在這種情況下,xargswhile都將在shell的子進程中運行(它們都並行運行,因此它們必須是單獨的進程)。

你將需要重構你的代碼,所以你不會積累在一個子shell中的值。其他人已經顯示了bash重構。這裏有一個方法,使用AWK:

find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du \ 
| awk '{sum += $1} END {print sum}' 

將在如果你想捕捉的變量之和的外殼功能:

sum_usage() { ...above pipeline... ; } 
totsize=$(sum_usage) 

你可以把它全部在$(...),但我覺得它更容易閱讀使用shell函數。

+0

+1用於提示shell函數 – sehe 2011-04-18 12:33:03

0

可能發生這種情況是因爲某些子shell創建(請參閱man bash,搜索命令執行環境)。

但您可以在不同時做:

find . -type f -mmin -4860 -a -mmin +3420 | xargs du | awk '{sum=sum+$1} END {print "Total: " sum " kb."}' 

HTH