使用 sed 或 nawk 计算列中替代值的总和

使用 sed 或 nawk 计算列中替代值的总和

foo.txt:

1  10     11
2   20     22
3   30     32
4   40     42
5   50     52
6   60     62
7   70     72
8   80     82
9   90     92
10  100   110

期望Out.txt

1  10     11
2   20     22
3   30     32
4   40     42
5   50     52
6   60     62
7   70     72
8   80     82
9   90     92
10  100   110
25  250   275   #Line 11
30  300   330   #Line 12
45  550   595  #Line 13

第 11 行是从第 1 行开始的第 1、第 2 和第 3 列中的交替行的总和,第 12 行是从第 2 行开始的第 1、第 2 和第 3 列中的交替行的总和。第 13 行是第 11 行和第 12 行中的列的总和。我使用的是 KSH 和 Solaris 5.10,输入文件中的值可能不是连续的,并且不会超过 3 位整数。我的输入文件只有 10 行。如何实现这一目标?

答案1

$ awk -v OFS='\t' '{for (i=1;i<=NF;i++) {s[2-NR%2,i]+=$i;s[3,i]+=$i;};$1=$1;print} END{for (n=1;n<=3;n++) print s[n,1],s[n,2],s[n,3]}' foo.txt 
1       10      11
2       20      22
3       30      32
4       40      42
5       50      52
6       60      62
7       70      72
8       80      82
9       90      92
10      100     110
25      250     259
30      300     318
55      550     577

以上是在 GNU awk 和 linux 上测试的。

怎么运行的

  • -v OFS='\t'

    可选:这将输出设置为制表符分隔。

  • {for (i=1;i<=NF;i++) {s[2-NR%2,i]+=$i;s[3,i]+=$i;}; $1=$1; print}

    这会循环遍历每一列,将其值添加到数组中s。对于每一列i,偶数行添加到s[2,i],奇数行添加到s[1,i]。所有行上的列i都添加到s[3,i].

    然后打印该行。

  • END{for (n=1;n<=3;n++) print s[n,1],s[n,2],s[n,3]}

    到达文件末尾后,将打印结果,首先打印奇数行 ( n=1),然后打印偶数行 ( n=2),最后打印总计 ( n=3)。

太阳/Solaris

我收到多个报告称 Sun/Solaris 上的默认 awk 有问题。请尝试:

nawk -v OFS='\t' '{for (i=1;i<=NF;i++) {s[2-NR%2,i]+=$i;s[3,i]+=$i;};$1=$1;print} END{for (n=1;n<=3;n++) print s[n,1],s[n,2],s[n,3]}' foo.txt 

或者:

/usr/xpg4/bin/awk -v OFS='\t' '{for (i=1;i<=NF;i++) {s[2-NR%2,i]+=$i;s[3,i]+=$i;};$1=$1;print} END{for (n=1;n<=3;n++) print s[n,1],s[n,2],s[n,3]}' foo.txt 

或者:

/usr/xpg6/bin/awk -v OFS='\t' '{for (i=1;i<=NF;i++) {s[2-NR%2,i]+=$i;s[3,i]+=$i;};$1=$1;print} END{for (n=1;n<=3;n++) print s[n,1],s[n,2],s[n,3]}' foo.txt 

答案2

您几乎肯定想使用awk这个,而不是sed.这是一个awk可以做到这一点的脚本:

awk '
    (NR%2) == 1 {
        odd_col_1 += $1;
        odd_col_2 += $2;
        odd_col_3 += $3;
        print $0;
    }
    (NR%2) == 0 {
        even_col_1 += $1;
        even_col_2 += $2;
        even_col_3 += $3;
        print $0;
    }
    END {
        print odd_col_1, odd_col_2, odd_col_3;
        print even_col_1, even_col_2, even_col_3;
        print odd_col_1+even_col_1, odd_col_2+even_col_2, odd_col_3 + even_col_3;
    }
' foo.txt

这利用了“NR”记录号内置变量、awk将文本文件分解为字段的方式以及“END”结构。

答案3

好吧,我自己找到了解决这个问题的一个非常基本的解决方案。但希望有人提供更好的答案。

#remove even lines
sed -i '0~2d' foo.txt > oddlines

#oddlines sum
awk '{a=a+$1}{b=b+$2}{c=c+$3}END{print a,b,c}' oddlines > oddlines_sum

#remove even lines
sed -i '1~2d' foo.txt > evenlines

#evenlines sum
awk '{a=a+$1}{b=b+$2}{c=c+$3}END{print a,b,c}' evenlines > evenlines_sum

#combine 
cat evenlines_sum >> oddlines_sum

#for total sum of foo.txt
awk '{a=a+$1}{b=b+$2}{c=c+$3}END{print a,b,c}' foo.txt > foo_sum

#final output
cat oddlines_sum >> foo.txt
cat foo_sum >> foo.txt`

我知道我的解决方案非常基本。但我尽力了。

答案4

sed '   1x;1s/^/654321/;1x;N;y/ /\n/;G;:t
        s/\([0-9]*\)\n*\n\(.*\)\(.\)/l\3\1+s\3 \2/;tt
        p;$!d;g;s/./l&/g;s/$/fcl3l6+l2l5+l1l4+f/' file |
dc 2>/dev/null |sed '11,$N;/\n/N;s/[^0-9] */\t/g' file -

这应该对你有用。它的工作原理是为带有流内的dc计算器/编译器处理一些宏预处理。sed

基本上,sed告诉dc bc的编译器 - 您应该在 Solaris 系统上拥有它)跟踪 6 个值,每隔一个输入行加载一次,每列递增它们,并再次保存结果。在最后一个输入行,sed告诉dc再次调用它们并将所有 6 个值打印到 stdout。要获得第 13 行的总计,我们所要做的就是再次调用存储的总计并将它们相加:

l3l6+...f

我们转储dc的 stderr ,/dev/null因为在第一行,当它尝试l从任何数组加载任何值时[123456],该数组仍为空,并且会发出警告。这没有任何意义,因为在其余时间它们不会为空,我们将在必要时保存/恢复它们。

最后,另一个sed将整个事情粘在一起 - 它将dc的输出附加到 的尾部file并用每行的一个制表符替换所有空格(我\t在这里使用了转义符,但它可能应该是实际脚本中的文字 <tab> 字符)

输出

1       10      11
2       20      22
3       30      32
4       40      42
5       50      52
6       60      62
7       70      72
8       80      82
9       90      92
10      100     110
25      250     259
30      300     318
55      550     577

相关内容