当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《Shell命令求和整数,每行一个?》经验,为你挑选了21个好方法。

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

作为一个背景,我有一个日志文件,其中包括时序测量,所以通过grepping相关的行,并稍微sed重新格式化,我可以列出该文件中的所有时间.然而,我想计算出总数,而且我的思绪已经变得空白,因为任何命令我都可以将这个中间输出传递到最终总和.我过去总是使用expr它,但除非它运行在sed我认为它不会应付这个(即使那样它也会很棘手).

我错过了什么?鉴于可能有多种方法可以实现这一点,我将很乐意阅读(和expr)任何有效的方法,即使其他人已经发布了一个不同的解决方案来完成这项工作.

相关问题:在Unix上计算一列输出总和的最短命令?(来自@Andrew)


更新:哇,正如所料,这里有一些不错的答案.看起来我一定要进行sed更深入的检查expr!



1> Paul Dixon..:

有点awk应该这样做吗?

awk '{s+=$1} END {print s}' mydatafile

注意:如果您要添加超过2 ^ 31(2147483647)的任何内容,某些版本的awk会有一些奇怪的行为.有关更多背景,请参阅评论 一个建议是使用printf而不是print:

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


在这个房间里有很多awk的爱!我喜欢如何通过将$ 1更改为$ 2来修改这样的简单脚本以添加第二列数据
注意,它不适用于大于2147483647的数字(即2 ^ 31),这是因为awk使用32位有符号整数表示.使用`awk'{s + = $ 1} END {printf"%.0f",s}'mydatafile`代替.
我曾经写过一个基本的邮件列表处理器,它带有一个通过休假实用程序运行的awk脚本.美好时光.:)
没有实际限制,因为它将输入作为流处理.因此,如果它可以处理X行的文件,你可以非常肯定它可以处理X + 1.
刚刚使用它来计算:计算所有文档的页面脚本:`ls $ @ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk'{s + = $ 2} END {print s}'`

2> 小智..:

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

paste -s -d+ infile | bc

或者,当从stdin管道时,

 | paste -s -d+ - | bc


比awk解决方案更容易记忆和输入.另外,请注意`paste`可以使用短划线`-`作为文件名 - 这将允许您将命令输出中的数字输入到paste的标准输出中,而无需先创建文件:` | 粘贴-sd + - | bc`
我有一个包含1亿个号码的文件.awk命令需要21s; paste命令需要41秒.但是很高兴见到'粘贴'!
@George你可以省略`-`.(如果要将文件*与*stdin组合,则非常有用).
@Abhi:有意思:DI猜测我需要花20秒才能找到awk命令,所以它会变得均匀,直到我尝试1亿和一个数字:D

3> dF...:

Python中的单行版本:

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


较短的版本是`python -c"import sys; print(sum(map(int,sys.stdin)))"`
我喜欢这个答案,因为它易于阅读和灵活.我需要在目录集合中小于10Mb的文件的平均大小,并将其修改为:`find.-name'*.epub'-exec stat -c%s'{}'\; | python -c"import sys; nums = [int(n)for sys.stdin中的n如果int(n)<10000000]; print(sum(nums)/ len(nums))"`

4> Giancarlo Sp..:

我会对通常认可的解决方案提出一个很大的警告:

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我本来想评论第一个答案,但我没有足够的声誉..


因为问题实际上是在"打印"功能中.Awk使用64位整数,但由于某种原因,打印将它们转换为32位.
打印错误似乎是固定的,至少对于awk 4.0.1和bash 4.3.11,除非我弄错了:`echo -e"2147483647 \n 100"| awk'{s + = $ 1} END {print s} '`显示`2147483747`
使用浮点数会带来一个新问题:`echo 9999999999999999999999 | awk'{s + = $ 1} END {printf“%.0f \ n”,s}'`产生`1000000000000000000`

5> Giacomo..:

普通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


较小的一个班轮:http://stackoverflow.com/questions/450799/linux-command-to-sum-integers-one-per-line/7720597#7720597
@Atcold这是`while`表达式中的'读数'.

6> CB Bailey..:
dc -f infile -e '[+z1

请注意,前缀为减号的负数应该被翻译dc,因为它使用_前缀而不是-前缀.例如,via tr '-' '_' | 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 [+?z1 dc只是使用的首选工具.但我会用更少的堆栈操作来做到这一点.假设所有行都包含一个数字:`(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
# 11s

AWK

:; 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
# 30s

C

仅仅为了比较,我编译了C版本并对其进行了测试,只是想知道基于工具的解决方案有多慢.

#include 
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

结论

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""+"
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

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有