【问题标题】:Subtracting the values in two rows using Awk使用 Awk 减去两行中的值
【发布时间】:2021-12-16 13:21:26
【问题描述】:

我是 awk 的新手,我正在尝试自学 bash,我发现 awk 真的很有趣,我只是想知道如何减去两行的值

34 43 67 87
21 22 64 43

这样我就达到了预期的输出

13 21 3 44

我的尝试

awk 'BEGIN{ FS = "\n" }{avgShirts=$1-$2}{print avgShirts}'

由于它只有两行,我尝试通过指定字段分隔符是一个新行但它不起作用。

【问题讨论】:

  • "\n" 通常用作行/记录分隔符;默认字段分隔符是空格(即空格或制表符)

标签: bash unix awk


【解决方案1】:

假设/理解:

  • 输入正好包含 2 行
  • 两行的字段/列数相同

输入:

$ cat 2rows.dat
34 43 67 87
21 22 64 43

一个awk想法:

awk '
NR==1 { for (i=1;i<=NF;i++)            # 1st line, loop through each field and ...
            fld[i]=$i                  # store each field in array fld[]
        next                           # skip the rest of the awk script and proceed to the next input line
      }
      { for (i=1;i<=NF;i++) {          # 2nd line, loop through each field and ...
            line=line pfx (fld[i]-$i)  # build output line based on difference of fields from 1st and 2nd lines
            pfx=OFS                    # 1st pass through loop pfx="", rest of loop pfx=" "
        }
        print line                     # print line of differences
      }
' 2rows.dat

这会生成:

13 21 3 44

另一个awk 想法,在计算总和时打印总和:

awk '
NR==1 { for (i=1;i<=NF;i++)
            fld[i]=$i
        next
      }
      { for (i=1;i<=NF;i++) {
            printf "%s%s", pfx, (fld[i]-$i)   # print prefix and current diff, since there is no "\n" we remain on the same output line for the next pass through the loop
            pfx=OFS
        }
        print ""                              # terminate line; same effect as: printf "\n"
      }
' 2rows.dat

这也会产生:

13 21 3 44

【讨论】:

  • pfx 做什么以及 OFS 是什么?
  • pfx 只是我对“前缀”的缩写,OFS 是单个空格的默认输出字段分隔符;第一次通过linepfx 是空的,所以line=line pfx (fld[i]-$i)line=(fld[i]-$i) 相同;如果pfx=OFS 在第一遍,那么输出行将有一个前导空格
【解决方案2】:

你可以这样做:

awk 'FNR%2{for (i=1;i<=NF;i++) arr[i]=$i; next}
     {for (i=1;i<=NF;i++) $i=arr[i]-$i} 1' file
13 21 3 44

解释:

# save every odd line 
FNR%2{for (i=1;i<=NF;i++) arr[i]=$i; next}

# every even line, subtract this field from the previous and print 
{for (i=1;i<=NF;i++) $i=arr[i]-$i} 1'

【讨论】:

  • 你介意解释一下为什么 NR==1 和 NR==2 而不是奇数甚至行不通,因为我试过了,但没有成功
  • 如果我将FNR%2 替换为NR==1,它的工作原理是一样的。注意NR是总记录,FNR是文件的记录...
  • 如果你不介意最后解释一下,1 是做什么的?
  • 1 评估为真。任何“真实”都会导致 awk 作为默认值打印或在 {action} 内部执行操作。在这种情况下,独立的 1 会导致打印。
【解决方案3】:
$ awk '
    NR==1 { split($0,minuends); next }
    {
        for (i=1; i<=NF; i++) {
            printf "%d%s", minuends[i] - $i, (i<NF ? OFS : ORS)
        }
    }
' file
13 21 3 44

如果您是 awk 的新手,请在手册页中查找 NR、NF、OFS、ORS 和 split()。您可以从 Arnold Robbins 的《Effective AWK Programming, 5th Edition》一书中学习 awk。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-22
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    相关资源
    最近更新 更多