如何快速求和文件中的所有数字?


16

每行在一行中包含文本和数字。我需要计算每一行中数字的总和。我怎样才能做到这一点?谢谢

example.log包含:

time=31sec
time=192sec
time=18sec
time=543sec

答案应该是784


我试过这种方法awk'{sum + = $ 1}; END {print sum}'example.log,但这仅适用于行中的数字
杰克

2
堆栈溢出中几乎存在相同的问题:如何快速求和文件中的所有数字?。也许有时间进行跨站点重复?
fedorqui

Answers:


18

如果您选择grep支持-o,则可以尝试:

$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc
784

适当地:

$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))"
784

16

使用GNU的较新版本(4.x)awk

awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'

与其他awk尝试:

awk -F '[a-z=]*' '{s+=$2}END{print s}'

4
您需要s+0在其中s为空的情况下,它将打印0而不是空白。
cuonglm

让我解释一下。-只有一种情况s可以为空;如果输入数据不包含任何行(即,如果根本没有输入)。在这种情况下,可能有两种行为;1)没有输入=>没有输出,或者2)总是输出某些东西(如果只有0)。根据应用程序的上下文,两者都是明智的选择。的+0被寻址选项2)。要解决选项1),您宁愿编写END {if(s) print s}。-因此,在问题指定之前,假设没有任何选择(对于这种无数据的极端情况)是没有意义的。
贾尼斯,2015年

10
awk -F= '{sum+=$2};END{print sum}'

2
我们更喜欢长格式的答案。您能详细说明一下它是如何工作的吗?
slm

2
@slm,这个答案与这里的其他答案相比,并没有更多或更少的冗长,是不言而喻的。它也有输入那样工作的优势time=1.4e5sec
斯特凡Chazelas

@StéphaneChazelas-同意,但这是一个新用户,我们鼓励用户提供不仅仅是单行的答案。一些文字解释它是如何工作的,将使它成为比代码更强大的答案。
slm

4
@slm,这是位拥有最佳答案之一的新用户(从技术角度来看),他获得了两个赞成票和负面评论。不是一个非常热烈的欢迎。
斯特凡Chazelas

1
@ TomFenech,awk的POSIX语法要求这些模式/操作项之间用“;”分隔;或“换行”,因此您可能会发现awk实现在没有此“;”的情况下失败。
斯特凡Chazelas

7

另一个GNU awk

awk -v RS='[0-9]+' '{n+=RT};END{print n}'

一个perl一个:

perl -lne'$n+=$_ for/\d+/g}{print$n'

POSIX一个:

tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc

6
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'

很棒的答案,但不需要sedawk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
user1717828 2015年

@ user1717828:您应该使用(更短,更兼容!)-F'='而不是--field-separator =
Olivier Dulac

@OlivierDulac,怪异,我man awk只给出了-F fs--field-separator fs
user1717828

@ user1717828:-F'='-F '='有两种方法-F fs(fs在您的情况下为“ =”)。我添加了单引号以确保fs可以正确地被awk看到并由awk解释,而不是由外壳程序解释(例如,如果fs为';',则为全用)
Olivier Dulac

4

您可以尝试以下方法:

awk -F"[^0-9]+" '{ sum += $2 } END { print sum+0; }' file

4

每个人都发布了很棒的awk答案,我非常喜欢。

@cuonglm的变体替换grepsed

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
  1. sed除了数字去掉一切。
  2. paste -sd+ -命令将所有行合并为一行
  3. bc计算表达式

3

您应该使用计算器。

{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null

用四行打印:

time=31
time=223
time=241
time=784

更简单地说:

tr times=c '    + p' <infile |dc

...打印

31
223
241
784

如果您追求的dc是速度,那么您想要的就是速度。传统上,它是bc的编译器-仍然适用于许多系统。


并非根据我的测量:这取决于您需要做多少工作才能生成公式
glenn jackman 2015年

@glennjackman- dc据我所知,您的测量值不包括在内。你在说什么?
mikeserv

顺便说一句,当将旧人员与新人员进行比较时(例如,当您perl使用标准unix工具集进行基准测试时),如果您使用在GNU工具链上编译的GNU工具,则并没有多大意义。所有能产生负面影响Perl的业绩膨胀的是同样所有的GNU编译GNU utils的的。悲伤但真实。您需要一个真正的,简单构建的简单工具集来准确判断差异。例如,就像一个传家宝工具集静态地与musl libs链接在一起-这样,您可以将单工具/单工作范式与单工具到规则的所有范式进行对比。
mikeserv


3

纯bash解决方案(Bash 3+):

while IFS= read -r line; do                   # While it reads a line:
    if [[ "$line" =~ [0-9]+ ]]; then      # If the line contains numbers:
        ((counter+=BASH_REMATCH[0]))          # Add the current number to counter
    fi                                    # End if.
done                                  # End loop.

echo "Total number: $counter"         # Print the number.
unset counter                         # Reset counter to 0.

精简版:

while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0

1
也许还会:PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.