【问题标题】:Bash command to sum a column of numbers [duplicate]Bash命令对一列数字求和[重复]
【发布时间】:2011-03-06 23:48:49
【问题描述】:

我想要一个 bash 命令,我可以通过管道将一列数字相加。我只想要一个快速的班轮,它基本上可以做这样的事情:

cat FileWithColumnOfNumbers.txt | sum

【问题讨论】:

标签: bash


【解决方案1】:

使用现有文件:

paste -sd+ infile | bc

使用标准输入:

<cmd> | paste -sd+ | bc

编辑: 对于一些 paste 实现,您需要在从 stdin 读取时更加明确:

&lt;cmd&gt; | paste -sd+ - | bc

使用的选项

-s (serial) - 将所有行合并为一行

-d - 使用非默认分隔符(在本例中为字符 +

【讨论】:

  • 应该有一个徽章。
  • 仅供参考,-s 选项在 GNU paste 中; Mac OS X 10.7.4 paste 不支持它。但是,由于paste 的POSIX 2008 规范支持-s,这是Mac OS X 版本中的一个缺陷。
  • 另一个 OS X 仅供参考,我必须在粘贴命令的末尾添加一个 - 才能在 OS X 10.6.8 上运行。
  • 使用bc -l,您甚至可以将浮点数相加。使用cut,您可以从输入中选择列:cat input.txt | cut -d ' ' -f 8 | paste -sd+ | bc -l 将在输入的第 8 列中添加所有浮点数(空格是字段分隔符)。
  • 嗯,使用 awk 会更容易:awk 'END { print s } { s += $8 }' infile :)
【解决方案2】:

我喜欢所选的答案。但是,它往往比 awk 慢,因为需要 2 个工具来完成这项工作。

$ wc -l file
49999998 file

$ time paste -sd+ file | bc
1448700364

real    1m36.960s
user    1m24.515s
sys     0m1.772s

$ time awk '{s+=$1}END{print s}' file
1448700364

real    0m45.476s
user    0m40.756s
sys     0m0.287s

【讨论】:

  • 好点!在 SunOS 5.8 bc 上,甚至核心转储都带有如此大的输入文件(请参阅下面的帖子)。
  • awk 是完成这项工作的正确工具! bc 解决方案还可以,但是当您需要对两列求和或过滤掉负数时会发生什么。使用 awk,您可以轻松而明智地添加额外的逻辑,使用 bc 解决方案,您最终会通过另一个命令(cut 或 grep)进行管道处理
  • @radoulov。谢谢。不知道 Solaris 的 bc 拒绝大量输入。
  • 我也会使用 awk,因为它允许通过 awk 'BEGIN{s=0}{s+=$1}END{print s}'s 初始化为 0。在这种情况下,如果将一个空列通过管道传输到paste | bc,则后一个管道将返回0 而不是null。 (在某些情况下,空列是合法输入)。
  • 这比选择的答案更通用、更快、更不脆弱。 +1 作为“如何在文件中添加一列数字”的最佳答案。选择的答案包括“如何在文件中仅添加一列数字。”
【解决方案3】:

以下命令将添加所有行(awk 输出的第一个字段)

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

【讨论】:

  • 这个适用于 mac OS 10.15
  • command | paste -s -d'+' - | bc 也可以在 mac OS 上运行
【解决方案4】:

两行算不算?

awk '{ sum += $1; }
     END { print sum; }' "$@"

然后你可以不用多余的“猫”来使用它:

sum < FileWithColumnOfNumbers.txt
sum   FileWithColumnOfNumbers.txt

FWIW:在 MacOS X 上,您可以使用单线来完成:

awk '{ sum += $1; } END { print sum; }' "$@"

【讨论】:

  • @jskaggz - 请参阅我的答案以获得更短/更简单的 Perl 版本:)
  • 单行 awk 适用于我尝试过的任何 awk,而不仅仅是 OS X
  • @unhammer:我无法再访问第 7 版 UNIX 及其 awk 版本。我不知道单行是否可以在那里工作,但是当我学习awk时我没有尝试过。你也许是对的; awk 的所有当前版本都可能支持单行。
  • $@ 是做什么的?它似乎对我使用 pbpaste 没有影响 | awk ...
  • @DavidMann: "$@" 在脚本中用于表示脚本的所有参数,如果没有参数,则表示无/无。如果您在pbpaste | awk … 中使用awk,则只需省略"$@"(尽管它通常不会造成损坏;终端上的大多数交互式shell 没有“位置参数”,因此"$@" 什么都不是)。但是如果你有一个 shell 脚本 sumcol1.sh,添加 "$@" 是明智的——然后你会使用 pbpaste | sumcol1.sh 或类似的,它会正常工作,sumcol1.sh file1 file2 也会正常工作。
【解决方案5】:

[ghostdog74s cmets 的后续]

bash-2.03$ uname -sr
SunOS 5.8

bash-2.03$ perl -le 'print for 1..49999998' > infile

bash-2.03$ wc -l infile
 49999998 infile

bash-2.03$  time paste -sd+ infile | bc
bundling space exceeded on line 1, teletype
Broken Pipe

real    0m0.062s
user    0m0.010s
sys     0m0.010s

bash-2.03$ time nawk '{s+=$1}END{print s}' infile
1249999925000001

real    2m0.042s
user    1m59.220s
sys     0m0.590s
bash-2.03$ time /usr/xpg4/bin/awk '{s+=$1}END{print s}' infile
1249999925000001

real    2m27.260s
user    2m26.230s
sys     0m0.660s

bash-2.03$ time perl -nle'
  $s += $_; END { print $s }
   ' infile
1.249999925e+15

real    1m34.663s
user    1m33.710s
sys     0m0.650s

【讨论】:

  • +1 用于指出此 bc 版本中的核心转储。我犹豫要不要更改这个问题的“答案”,因为 bc 版本对我来说很好(我总共有 30 个数字)。
  • perl 版本 +1 - 在我的 ubuntu 12.04 上最快
  • +1 用于处理浮点数的 Perl 版本。此外,对于我正在寻找的内容,这里对特定列(从零开始索引的第 2 列)求和:perl -nle '$s += (split)[2]; END { print $s }' foo.txt 或使用管道:cat foo.txt | perl -nle '$s += (split)[2]; END { print $s }'
  • 另外:paste -sd+ -|perl -nle 'print eval'
【解决方案6】:

您可以使用 bc(计算器)。假设带有#s 的文件称为“n”:

$ cat n
1
2
3
$ (cat n | tr "\012" "+" ; echo "0") | bc 
6

tr 将所有换行符更改为“+”;然后我们在最后一个加号后附加 0,然后我们将表达式 (1+2+3+0) 传递给计算器

或者,如果您可以使用 awk 或 perl,这里有一个 Perl 单行:

$perl -nle '$sum += $_ } END { print $sum' n
6

【讨论】:

  • 对于 perl,这也可以:perl -nle '$s+=$_}{print $s' 它有点简单。 :)
【解决方案7】:
while read -r num; do ((sum += num)); done < inputfile; echo $sum

【讨论】:

  • 如果你有很多数字要添加,这不是很好:使用@radulov 的文件,这需要 10 分 28 秒(Ubuntu 12.04)。 perl 解决方案耗时 11 秒,awk 耗时 13 秒,|bc 耗时 37 秒。
  • @drevicko 另一方面,如果没有很多数字要添加(jskaggz 告诉他需要 30 个数字),这种方式是最快的,因为没有分叉!跨度>
  • @techno 确实如此,尽管只有一个分叉。另一方面,对于 30 个数字,速度有点无关紧要 - 最好使用您最熟悉的工具,例如 bash (:
  • 嘿嘿,这其实是第一个回答的问题(“如何用 bash 对列求和”)。
【解决方案8】:

使用for 循环遍历您的文件……

sum=0; for x in `cat <your-file>`; do let sum+=x; done; echo $sum

【讨论】:

  • 没有cat :: for s in $(&lt; infile); do let sum+=$s ; done &amp;&amp; echo $sum
  • 这不适用于浮点数
【解决方案9】:

如果你安装了 ruby​​

cat FileWithColumnOfNumbers.txt | xargs ruby -e "puts ARGV.map(&:to_i).inject(&:+)"

【讨论】:

    【解决方案10】:
    [root@pentest3r ~]# (find / -xdev -size +1024M) | (while read a ; do aa=$(du -sh $a | cut -d "." -f1 ); o=$(( $o+$aa )); done; echo "$o";)
    

    【讨论】:

    • 问题的一部分答案隐藏在一些相当晦涩的脚本中,该脚本会找到大文件并在每个文件上分别运行du,这既痛苦又在很大程度上无关紧要。另一个较旧的答案提供了相同的“仅使用 shell”解决方案。鉴于没有解释和重复另一个答案和离题编码,保留这个答案确实没有任何好处。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 2018-10-28
    • 2021-03-09
    • 2012-08-15
    • 1970-01-01
    • 2013-05-17
    相关资源
    最近更新 更多