Shell命令对整数求和,每行一个?

Shell命令对整数求和,每行一个?,shell,Shell,我正在寻找一个命令,它将接受(作为输入)多行文本,每行包含一个整数,并输出这些整数的总和 作为一个背景,我有一个日志文件,其中包括计时测量。通过对相关行进行grepping和一点sed重新格式化,我可以列出该文件中的所有计时。我想算出总数。我可以通过管道将这个中间输出传输到任何命令,以便进行最终的求和。我过去一直使用expr,但除非它在RPN模式下运行,否则我认为它无法解决这个问题(即使这样也会很棘手) 如何获得整数的总和?perl-lne'$x+=$\ux;结束{print$x;}'

我正在寻找一个命令,它将接受(作为输入)多行文本,每行包含一个整数,并输出这些整数的总和

作为一个背景,我有一个日志文件,其中包括计时测量。通过对相关行进行grepping和一点
sed
重新格式化,我可以列出该文件中的所有计时。我想算出总数。我可以通过管道将这个中间输出传输到任何命令,以便进行最终的求和。我过去一直使用
expr
,但除非它在RPN模式下运行,否则我认为它无法解决这个问题(即使这样也会很棘手)

如何获得整数的总和?

perl-lne'$x+=$\ux;结束{print$x;}'perl -lne '$x += $_; END { print $x; }' < infile.txt

一点awk就可以了

awk '{s+=$1} END {print s}' mydatafile
注意:如果要添加任何超过2^31(2147483647)的内容,awk的某些版本会有一些奇怪的行为。有关更多背景信息,请参阅评论。一个建议是使用
printf
而不是
print

awk '{s+=$1} END {printf "%.0f", s}' mydatafile

如果您觉得舒服,可以使用python进行:

未测试,仅键入:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s
塞巴斯蒂安指出了一个单行脚本:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"

在bash中可以执行以下操作:

I=0

for N in `cat numbers.txt`
do
    I=`expr $I + $N`
done

echo $I

Python中的一行程序版本:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"

BASH解决方案,如果您希望将其作为命令(例如,如果您需要经常这样做):

然后使用:

addnums < /tmp/nums
addnums
普通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
$cat numbers.txt
1.
2.
3.
4.
5.
6.
7.
8.
9
10
$sum=0;同时读取num;do((sum+=num));done
以下各项应该有效(假设您的号码是每行的第二个字段)


您可以使用num-utils,尽管这对于您所需要的可能有些过分。这是一组用于在shell中处理数字的程序,可以做一些漂亮的事情,当然包括将它们相加。这有点过时了,但它们仍然有效,如果你需要做更多的事情,它们会很有用

它的使用非常简单:

$ seq 10 | numsum
55
但是对于大的输入,内存不足

$ seq 100000000 | numsum
Terminado (killed)

“粘贴”通常会合并多个文件的行,但也可用于将文件的单个行转换为一行。分隔符标志允许您将x+x类型方程式传递给bc

paste -s -d+ infile | bc
或者,当从标准DIN连接管道时

<commands> | paste -s -d+ - | bc
|粘贴-s-d+-|bc
作为伪代码:

  • 将“添加\u堆栈顶部\u”定义为:
  • 从堆栈中删除两个顶部值,然后将结果添加回堆栈
  • 如果堆栈有两个或多个值,则递归运行“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执行一些命令
    寄存器={'r':无}
    堆栈=[]
    def add():
    stack.append(stack.pop()+stack.pop())
    def z():
    stack.append(len(stack))
    无def(reg):
    如果stack.pop()
    我意识到这是一个老问题,但我非常喜欢这个解决方案,可以与大家分享

    % cat > numbers.txt
    1 
    2 
    3 
    4 
    5
    ^D
    % cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
    15
    
    如果有兴趣,我会解释它是如何工作的

    $ cat n 2 4 2 7 8 9 $cat n 2. 4. 2. 7. 8. 9
    $perl-MList::Util-le'print List::Util::sum()
    32
    
    或者,您可以在命令行中键入数字:

    $ perl -MList::Util -le 'print List::Util::sum(<>)'
    1
    3
    5
    ^D
    9
    
    $perl-MList::Util-le'print List::Util::sum()
    1.
    3.
    5.
    ^D
    9
    
    但是,这个文件会发出声音,所以在大文件上使用它不是一个好主意。看看哪一个可以避免发出咕噜声。

    简单地击打一个衬垫

    $ cat > /tmp/test
    1 
    2 
    3 
    4 
    5
    ^D
    
    $ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
    
    C++(简化):

    SCC项目-


    SCC是shell提示中的C++片段评估器,预先对后台(“”)的可读性进行道歉,但这些工作在BASH以外的shell中,因此更易于巴氏。如果您使用一个接受它的shell,$(command…)格式比'command…'更具可读性(因此也更易于调试),因此请随意修改以保持理智

    我的bashrc中有一个简单的函数,它将使用awk来计算一些简单的数学项

    calc(){
      awk 'BEGIN{print '"$@"' }'
    }
    
    这将完成+、-、*、/、^、%、sqrt、sin、cos、括号……(更多取决于您的awk版本)。。。您甚至可以使用printf和格式化浮点输出,但这是我通常需要的全部

    对于这个特定的问题,我只需对每一行进行以下操作:

    calc `echo "$@"|tr " " "+"`
    
    因此,对每行求和的代码块如下所示:

    while read LINE || [ "$LINE" ]; do
      calc `echo "$LINE"|tr " " "+"` #you may want to filter out some lines with a case statement here
    done
    
    如果你只想逐行求和。但是,对于数据文件中的所有数字

    VARS=`<datafile`
    calc `echo ${VARS// /+}`
    

    纯bash和一行中:-)

    球拍中的一个衬垫:

    racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt
    
    racket-e'(define(g)(define i(read))(if(eof object?i)empty(cons i(g)))(foldr+0(g))”
    纯粹而简短的bash

    f=$(cat numbers.txt)
    echo $(( ${f//$'\n'/+} ))
    
    C(不简化)

    seq 1 10 | tcc-运行我的15美分:

    $ 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
    
    我的版本:

    seq -5 10 | xargs printf "- - %s" | xargs  | bc
    

    我要对普遍认可的解决方案提出一个严重警告:

    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
    
    与:


    可选纯Perl,可读性强,不需要包或选项:

    perl -e "map {$x += $_} <> and print $x" < infile.txt
    
    perl-e“映射{$x+=$\}并打印$x”
    适合红宝石爱好者

    ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
    

    无法避免提交此文件,这是解决此问题的最通用方法,请检查:

    jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc
    
    它是f
    f=$(cat numbers.txt)
    echo $(( ${f//$'\n'/+} ))
    
    seq 1 10 | tcc -run <(cat << EOF
    #include <stdio.h>
    int main(int argc, char** argv) {
        int sum = 0;
        int i = 0;
        while(scanf("%d", &i) == 1) {
            sum = sum + i;
        }
        printf("%d\n", sum);
        return 0;
    }
    EOF)
    
    $ 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
    
    seq -5 10 | xargs printf "- - %s" | xargs  | bc
    
    awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!
    
    awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
    
    seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
    
    perl -e "map {$x += $_} <> and print $x" < infile.txt
    
    ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
    
    jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc
    
    :; 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
    # 11s
    
    :; seq 100000000 | awk '{s+=$1} END {print s}'
    5000000050000000
    # 22s
    
    :; seq 50000000 | paste -s -d+ - | bc
    1250000025000000
    # 17s
    :; seq 50000001 100000000 | paste -s -d+ - | bc
    3750000025000000
    # 18s
    
    :; 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
    # 30s
    
    #include <stdio.h>
    int 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
    
    seq 10 | datamash sum 1
    
    55
    
    <commands...> | datamash -W sum 1
    
    <commands...> | tr -d '[[:blank:]]' | datamash sum 1
    
    seq 100000000 | datamash sum 1
    
    5.00000005e+15
    
    seq 100000000 | datamash  --format '%.0f' sum 1
    
    5000000050000000