我正在寻找一个命令,它将接受多行文本作为输入,每行包含一个整数,并输出这些整数的总和.
作为一个背景,我有一个日志文件,其中包括时序测量,所以通过grepping相关的行,并稍微sed
重新格式化,我可以列出该文件中的所有时间.然而,我想计算出总数,而且我的思绪已经变得空白,因为任何命令我都可以将这个中间输出传递到最终总和.我过去总是使用expr
它,但除非它运行在sed
我认为它不会应付这个(即使那样它也会很棘手).
我错过了什么?鉴于可能有多种方法可以实现这一点,我将很乐意阅读(和expr
)任何有效的方法,即使其他人已经发布了一个不同的解决方案来完成这项工作.
相关问题:在Unix上计算一列输出总和的最短命令?(来自@Andrew)
更新:哇,正如所料,这里有一些不错的答案.看起来我一定要进行sed
更深入的检查expr
!
有点awk应该这样做吗?
awk '{s+=$1} END {print s}' mydatafile
注意:如果您要添加超过2 ^ 31(2147483647)的任何内容,某些版本的awk会有一些奇怪的行为.有关更多背景,请参阅评论 一个建议是使用printf
而不是print
:
awk '{s+=$1} END {printf "%.0f", s}' mydatafile
粘贴通常合并多个文件的行,但它也可用于将文件的各行转换为单行.分隔符标志允许您将x + x类型方程传递给bc.
paste -s -d+ infile | bc
或者,当从stdin管道时,
| paste -s -d+ - | bc
Python中的单行版本:
$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
我会对通常认可的解决方案提出一个很大的警告:
awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!
这是因为在这种形式下,awk使用32位有符号整数表示:对于超过2147483647(即2 ^ 31)的和,它将溢出.
更一般的答案(对于求和整数)将是:
awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
PS我本来想评论第一个答案,但我没有足够的声誉..
普通bash:
$ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 $ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum 55
dc -f infile -e '[+z1请注意,前缀为减号的负数应该被翻译
dc
,因为它使用_
前缀而不是-
前缀.例如,viatr '-' '_' | dc -f- -e '...'
.编辑:由于这个答案得到了很多"默默无闻"的投票,这里有一个详细的解释:
表达式
[+z1
执行以下操作: [ interpret everything to the next ] as a string + push two values off the stack, add them and push the result z push the current stack depth 1 push one作为伪代码:
将"add_top_of_stack"定义为:
从堆栈中删除两个顶部值并将结果添加回来
如果堆栈有两个或更多值,则递归运行"add_top_of_stack"
如果堆栈有两个或更多值,请运行"add_top_of_stack"
打印结果,现在是堆栈中剩下的唯一项目
为了真正理解它的简单性和强大功能
dc
,这里有一个有效的Python脚本,可以实现dc
上述命令的Python版本并执行它们:### Implement some commands from dc registers = {'r': None} stack = [] def add(): stack.append(stack.pop() + stack.pop()) def z(): stack.append(len(stack)) def less(reg): if stack.pop() < stack.pop(): registers[reg]() def store(reg): registers[reg] = stack.pop() def p(): print stack[-1] ### Python version of the dc command above # The equivalent to -f: read a file and push every line to the stack import fileinput for line in fileinput.input(): stack.append(int(line.strip())) def cmd(): add() z() stack.append(1) less('r') stack.append(cmd) store('r') z() stack.append(1) less('r') p()
在线算法:`dc -e'0 0 [+?z1dc只是使用的首选工具.但我会用更少的堆栈操作来做到这一点.假设所有行都包含一个数字:`(echo"0"; sed的/ $/+ /'inp; echo'pq')| dc`.
7> banyan..:用jq:
seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
我喜欢这个,因为我觉得它是如此清晰和短暂,以至于我实际上可以记住它.
8> 小智..:纯粹和短暂的bash.
f=$(cat numbers.txt) echo $(( ${f//$'\n'/+} ))
这是最好的解决方案,因为如果用`f = $(@loentar`
9> j_random_hac..:perl -lne '$x += $_; END { print $x; }' < infile.txt
我把它们添加回去:" - l"确保输出是LF终止的,因为shell``反引号和大多数程序所期望的,而"<"表示此命令可以在管道中使用.
少数解决方案之一,不会将所有内容加载到RAM中.
10> innocent-wor..:我十五美分:
$ cat file.txt | xargs | sed -e 's/\ /+/g' | bc例:
$ cat text 1 2 3 3 4 5 6 78 9 0 1 2 3 4 576 7 4444 $ cat text | xargs | sed -e 's/\ /+/g' | bc 5148
11> Alfe..:我已经对现有答案做了快速基准测试
只使用标准工具(抱歉
lua
或类似的东西rocket
),是真正的单行,
能够增加大量的数字(1亿),和
很快(我忽略了花了一分多钟的那些).
对于多种解决方案,我总是在不到一分钟的时间内添加了1到1亿的数字,这在我的机器上是可行的.
结果如下:
蟒蛇
:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))' 5000000050000000 # 30s :; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)' 5000000050000000 # 38s :; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))' 5000000050000000 # 27s :; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))' 5000000050000000 # 22s :; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))' 5000000050000000 # 11s :; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))' 5000000050000000 # 11sAWK
:; seq 100000000 | awk '{s+=$1} END {print s}' 5000000050000000 # 22s粘贴&Bc
这在我的机器上耗尽了内存.它的工作量只有输入的一半(5000万个数字):
:; seq 50000000 | paste -s -d+ - | bc 1250000025000000 # 17s :; seq 50000001 100000000 | paste -s -d+ - | bc 3750000025000000 # 18s所以我想这对于1亿个数字来说需要大约35秒.
Perl的
:; seq 100000000 | perl -lne '$x += $_; END { print $x; }' 5000000050000000 # 15s :; seq 100000000 | perl -e 'map {$x += $_} <> and print $x' 5000000050000000 # 48s红宝石
:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)" 5000000050000000 # 30sC
仅仅为了比较,我编译了C版本并对其进行了测试,只是想知道基于工具的解决方案有多慢.
#includeint main(int argc, char** argv) { long sum = 0; long i = 0; while(scanf("%ld", &i) == 1) { sum = sum + i; } printf("%ld\n", sum); return 0; }
:; seq 100000000 | ./a.out 5000000050000000 # 8s结论
C当然是最快的8s,但Pypy解决方案只增加了大约30%到11s的非常小的开销.但是,公平地说,Pypy并不完全是标准的.大多数人只安装了CPython,速度要慢得多(22秒),与流行的Awk解决方案一样快.
基于标准工具的最快解决方案是Perl(15s).
12> Jay..:BASH解决方案,如果你想让它成为一个命令(例如,如果你需要经常这样做):
addnums () { local total=0 while read val; do (( total += val )) done echo $total }然后用法:
addnums < /tmp/nums
13> Khaja Minhaj..:普通bash一个衬垫
$ cat > /tmp/test 1 2 3 4 5 ^D $ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
不需要_cat_:`echo $(($(tr"\n""+" tmp/test)0))`
14> Paolo..:我认为AWK正是您所寻找的:
awk '{sum+=$1}END{print sum}'您可以通过将数字列表传递到标准输入或将包含数字的文件作为参数传递来使用此命令.
这是一个重复:http://stackoverflow.com/questions/450799/linux-command-to-sum-integers-one-per-line#450821
15> Francisco Ca..:以下在bash中有效:
I=0 for N in `cat numbers.txt` do I=`expr $I + $N` done echo $I
16> sykora..:你可以使用num-utils,虽然它可能对你需要的东西有点过分.这是一组用于操作shell中的数字的程序,可以做几个很好的事情,当然包括添加它们.它有点过时,但它们仍然有用,如果你需要做更多的事情,它们会很有用.
http://suso.suso.org/programs/num-utils/
17> 小智..:sed 's/^/.+/' infile | bc | tail -1
18> Nym..:我意识到这是一个老问题,但我喜欢这个解决方案足以分享它.
% cat > numbers.txt 1 2 3 4 5 ^D % cat numbers.txt | perl -lpe '$c+=$_}{$_=$c' 15如果有兴趣,我会解释它是如何工作的.
请不要.我们喜欢假装-n和-p是很好的语义事物,而不仅仅是一些聪明的字符串粘贴;)
是的,请解释一下:)(我不是Perl typea家伙。)
19> 小智..:纯粹的bash和单线:-)
$ cat numbers.txt 1 2 3 4 5 6 7 8 9 10 $ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I 55
20> 小智..:替代纯Perl,相当可读,不需要包或选项:
perl -e "map {$x += $_} <> and print $x" < infile.txt
21> johnlinvc..:对于Ruby Lovers
ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt