如何在Bash中添加一列数字
介绍
本文研究了如何在bash shell中对数据的数字列进行累加,研究了可用于该任务的bash工具并比较了它们的速度。
使用awk工具
$ awk '{Total=Total+$1} END{print "Total is: " Total}' numbers.csv
Total is: 49471228
现在让我们用 “时间 “命令来看看计时的情况 —
$ time awk '{Total=Total+$1} END{print "Total is: " Total}' numbers.csv
Total is: 49471228
real 0m0.228s
user 0m0.141s
sys 0m0.047s
当文件包含多列时
我们已经看到了如何使用awk来计算文件中一行的总和。现在让我们来看看如何计算一个文件中多行的总和。
$ cat prices.csv
Books,40
Bag,70
Dress,80
Box,10
这里,文件price.csv有两列。我们现在要计算第二列中的数值之和。
$ awk -F "," '{Total=Total+$2} END{print "Total is: " Total}' prices.csv
Total is: 200
当文件包含一个标题行时
有时,文本或CSV文件的标题也包括包含列名的一行。我们将使用这些列名来帮助我们理解文件的内容。让我们编辑我们的price.csv文件,并在顶部添加一个新的行–
$ cat prices.csv
Item,Value
Books,40
Bag,70
Dress,80
Box,10
当文件包括一个标题时,我们要在文本处理发生之前删除标题。首先,让我们给我们的输入数据集添加一个额外的字段,称为 “标题”。然后,我们写一个脚本,读取文件中的每一条记录,并将新字段的值加到总数中。最后,我们将打印出结果。
$ awk -F "," 'NR!=1{Total=Total+$2} END{print "Total is: " Total}' prices.csv
Total is: 200
然后我们将看看其他一些在一列中进行加法的方法,并看看awk的方法与它们相比如何。
用Bash循环进行迭代
Awk是一个强大的工具,但我们也可以使用for循环来迭代我们列中的每个值。
使用expr命令
我们要做一个实验,看看我们是否能用expr函数来计算for循环里面的数字的总和。
$ time (sum=0;for number in `cat numbers.csv`; do sum=`expr $sum + $number`; done; echo "Total is: $sum")
Total is: 49471228
real 212m48.418s
user 7m19.375s
sys 145m48.203s
使用算术扩展
由于使用 “扩展 “没有什么帮助,我们将尝试另一种方法,使用算术表达式–
$ time (sum=0;for number in `cat numbers.csv`; do sum=$((sum+number)); done; echo "Total is: $sum")
Total is: 49471228
real 0m1.961s
user 0m1.813s
sys 0m0.125s
为了计算总数,我们将利用算术运算符。与expr运算符不同,$ (…)运算符可以处理整数和浮点数。
用bc命令添加值
bc命令对由多行组成的表达式进行计算。因此,我们必须将这些数字串联成一行,用加法运算符将它们分开。然后我们将产生的字符串传递给bc来执行计算。这里有几种方法可以做到这一点。
使用 “paste “命令
首先,我们来看看 “PASET “命令,将我们数据集的前十个数字排列在一行。
$ cat numbers.csv| head -10 | paste -sd+ -
2+44+6+15+23+0+15+88+82+1
选项-s确保粘贴时将每个条目打印在自己的行中。我们还使用了+d选项,在每个条目之间添加 “+”符号作为分隔符。
现在我们已经涵盖了基础知识,让我们继续向bc命令提供我们的输入。
$ time echo "Total is: $(cat numbers.csv | paste -sd+ - | bc)"
Total is: 49471228
real 0m0.244s
user 0m0.203s
sys 0m0.063s
使用 tr 命令
让我们再次使用tr(音译)函数,从一个现有的字符串中创建一个新的字符串。
$ cat numbers.csv | head -10 |tr "
" "+"
2+44+6+15+23+0+15+88+82+1+
我们在字符串的开头多加了一个0,这样我们就可以使用bc命令来进行加法运算。然而,注意到在字符串的末尾多了一个’+’。为了解决这个问题,我们可以简单地在行末追加一个零。
$ cat numbers.csv | head -10 |tr "
" "+" ; echo "0"
2+44+6+15+23+0+15+88+82+1+0
让我们把上一条命令的结果重定向到bc命令中。
$ time ((cat numbers.csv | tr "
" "+" ; echo "0") | bc)
49471228
real 0m0.217s
user 0m0.203s
sys 0m0.031s
结合使用tr和bc命令比使用awk运行得更快。
使用sed命令
我们最后将使用sed命令来生成我们的序列。
$ cat numbers.csv | head -10 | sed -z 's#
#+#g'
2+44+6+15+23+0+15+88+82+1+
我们已经更换了新的线路(”
“)与加号(”+”)运算符,使用sed命令的搜索和替换选项,并在结尾处打印零来处理额外的加号运算符。
$ time ((cat numbers.csv | sed -z 's#
#+#g' ; echo "0") | bc)
49471228
real 0m0.343s
user 0m0.281s
sys 0m0.109s
要改变换行的含义,请使用”-z “选项。现在它们将被视为空字符,而不是将换行线解释为每个输入的开始。
如果你要处理大量的文本,你可能想用sed而不是tr。
结论
我们研究了在bash shell中对各列数字进行加法的不同方法。
我们首先讨论了awk命令的使用。然后我们讨论了处理包含多列或带有标题的单列的文件的方法。