【发布时间】:2011-03-06 23:48:49
【问题描述】:
我想要一个 bash 命令,我可以通过管道将一列数字相加。我只想要一个快速的班轮,它基本上可以做这样的事情:
cat FileWithColumnOfNumbers.txt | sum
【问题讨论】:
-
仅供参考,
awk解决方案既是 easier to remember,速度也快了大约 2 倍(参见 here 和 here)。
标签: bash
我想要一个 bash 命令,我可以通过管道将一列数字相加。我只想要一个快速的班轮,它基本上可以做这样的事情:
cat FileWithColumnOfNumbers.txt | sum
【问题讨论】:
awk 解决方案既是 easier to remember,速度也快了大约 2 倍(参见 here 和 here)。
标签: bash
paste -sd+ infile | bc
<cmd> | paste -sd+ | bc
编辑: 对于一些 paste 实现,您需要在从 stdin 读取时更加明确:
<cmd> | paste -sd+ - | bc
使用的选项:
-s (serial) - 将所有行合并为一行
-d - 使用非默认分隔符(在本例中为字符
+)
【讨论】:
-s 选项在 GNU paste 中; Mac OS X 10.7.4 paste 不支持它。但是,由于paste 的POSIX 2008 规范支持-s,这是Mac OS X 版本中的一个缺陷。
bc -l,您甚至可以将浮点数相加。使用cut,您可以从输入中选择列:cat input.txt | cut -d ' ' -f 8 | paste -sd+ | bc -l 将在输入的第 8 列中添加所有浮点数(空格是字段分隔符)。
awk 'END { print s } { s += $8 }' infile :)
我喜欢所选的答案。但是,它往往比 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
【讨论】:
awk 'BEGIN{s=0}{s+=$1}END{print s}' 将 s 初始化为 0。在这种情况下,如果将一个空列通过管道传输到paste | bc,则后一个管道将返回0 而不是null。 (在某些情况下,空列是合法输入)。
以下命令将添加所有行(awk 输出的第一个字段)
awk '{s+=$1} END {print s}' filename
【讨论】:
command | paste -s -d'+' - | bc 也可以在 mac OS 上运行
两行算不算?
awk '{ sum += $1; }
END { print sum; }' "$@"
然后你可以不用多余的“猫”来使用它:
sum < FileWithColumnOfNumbers.txt
sum FileWithColumnOfNumbers.txt
FWIW:在 MacOS X 上,您可以使用单线来完成:
awk '{ sum += $1; } END { print sum; }' "$@"
【讨论】:
awk 版本。我不知道单行是否可以在那里工作,但是当我学习awk时我没有尝试过。你也许是对的; awk 的所有当前版本都可能支持单行。
"$@" 在脚本中用于表示脚本的所有参数,如果没有参数,则表示无/无。如果您在pbpaste | awk … 中使用awk,则只需省略"$@"(尽管它通常不会造成损坏;终端上的大多数交互式shell 没有“位置参数”,因此"$@" 什么都不是)。但是如果你有一个 shell 脚本 sumcol1.sh,添加 "$@" 是明智的——然后你会使用 pbpaste | sumcol1.sh 或类似的,它会正常工作,sumcol1.sh file1 file2 也会正常工作。
[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
【讨论】:
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'
您可以使用 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 -nle '$s+=$_}{print $s' 它有点简单。 :)
while read -r num; do ((sum += num)); done < inputfile; echo $sum
【讨论】:
使用for 循环遍历您的文件……
sum=0; for x in `cat <your-file>`; do let sum+=x; done; echo $sum
【讨论】:
cat :: for s in $(< infile); do let sum+=$s ; done && echo $sum
如果你安装了 ruby
cat FileWithColumnOfNumbers.txt | xargs ruby -e "puts ARGV.map(&:to_i).inject(&:+)"
【讨论】:
[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”解决方案。鉴于没有解释和重复另一个答案和离题编码,保留这个答案确实没有任何好处。