考虑:
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"
打印“Sum:0 kb”,即使临时打印语句打印出合理的总和。
我知道我以前遇到过这个问题,但从未理解过。有什么区别?
答案 0 :(得分: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)
subprocess | do_something
答案 1 :(得分: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"}'
答案 2 :(得分:1)
这是一个常见问题。管道的右侧元素在子shell中运行。在这种情况下,xargs
和while
都将在shell的子进程中运行(它们都是并行运行的,因此它们必须是单独的进程)。
您需要重构代码,这样才不会在子shell中累积值。其他人已经展示了bash重构。这是使用awk的方法:
find /home/user -type f -mmin -4860 -a -mmin +3420 | xargs du \
| awk '{sum += $1} END {print sum}'
如果要捕获变量中的总和,请将其置于shell函数中:
sum_usage() { ...above pipeline... ; }
totsize=$(sum_usage)
你可以将它全部放在$(...)
中,但我认为使用shell函数更容易阅读。
答案 3 :(得分:0)
可能是因为创建了一些子shell(请参阅man bash
,搜索命令执行环境)。
但你可以在没有的时候做到:
find . -type f -mmin -4860 -a -mmin +3420 | xargs du | awk '{sum=sum+$1} END {print "Total: " sum " kb."}'
HTH