我有一个文件,其中包含许多行和 5 列的数字,如下所示:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...
如果我想以这种方式获得第一行和第三行中的数字之和: 1+11, 2+12, 3+13, 4+14, 5+15 这意味着我最终想看到的是12 14 16 18 20
应该我愿意?
答案1
解决方案1
#!/bin/bash
{ read -ra line1; read _; read -ra line3; }
for i in "${!line1[@]}"; do
result+=("$(( ${line1[i]} + ${line3[i]} ))")
done
printf %s\\n "${result[*]}"
例子:
$ bash script < yourfilename
12 14 16 18 20
$
脚本说明
{ read -ra line1; read _; read -ra line3; }
这部分读取文件的前三行,仅保留前两行。它还将它们分成数组 line1 和 line3。它假定来自标准输入的数据流。请参阅有关如何执行此操作的示例。
for i in "${!line1[@]}"; do result+=("$(( ${line1[i]} + ${line3[i]} ))"); done
此部分循环遍历两个数组之一的元素,并对 line1 和 line2 中的相同元素求和。结果被放入一个名为 result 的新数组中
printf %s\\n "${result[*]}"
以空格分隔打印计算出的数组元素。
解决方案2
另一种避免循环的解决方案,假设输入按要求有 5 列:
#!/bin/bash
{ read a b c d e; read _; read v w x y z; }
echo "$((a+v)) $((b+w)) $((c+x)) $((d+y)) $((e+z))"
例子:
$ cat yourfilename
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...
$ bash script < yourfilename
12 14 16 18 20
$
脚本说明
{ read a b c d e; read _; read v w x y z; }
将第 1 行(或第 3 行)中的数字读入变量 a 至 e(或 v 至 z)
echo "$((a+v)) $((b+w)) $((c+x)) $((d+y)) $((e+z))"
根据要求打印以空格分隔的变量的总和
答案2
$ sed -n '1p;3p' file | datamash -W sum 1-5
12 14 16 18 20
首先sed
仅用于输出第 1 行和第 3 行。然后将它们输入到 GNU 中datamash
,GNU 被告知对第 1 列到第 5 列中的每个单独列求和。它-W
指示datamash
将任何连续的空格视为字段分隔符。
输出以制表符分隔。要获得空格分隔的输出,请使用--output-delimiter=' '
以下选项datamash
:
$ sed -n '1p;3p' file | datamash -W --output-delimiter=' ' sum 1-5
12 14 16 18 20
答案3
awk 'NR==1 || NR==3 { for (i=1; i<=NF; i++) a[i]+=$(i)}END{for (i in a) printf "%s ", a[i]; print ""}'
例子:
$ awk 'NR==1 || NR==3 { for (i=1; i<=NF; i++) a[i]+=$(i)}END{for (i in a) printf "%s ", a[i]; print ""}'' yourfilename
12 14 16 18 20
$
编辑:要在第三个之后停止从文件中读取行,我们可以提前退出。不过,对于包含少于 10k 行的文件,您不会看到明显的差异。
awk 'NR==1 {split($0,a)} NR==3 {for (i in a) printf "%s ", a[i]+$i; print ""; exit}'
证明它适用于您的示例:
$ cat yourfilename
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
...
$ awk 'NR==1 {split($0,a)} NR==3 {for (i in a) printf "%s ", a[i]+$i; print ""; exit}' yourfilename
12 14 16 18 20
$