【问题标题】:How to Compare CSV Column using awk?如何使用 awk 比较 CSV 列?
【发布时间】:2016-06-08 22:25:21
【问题描述】:

我收到这样的 CSV:

column$1,column$2,column$
john,P,10
john,P,10
john,A,20
john,T,30
john,T,10
marc,P,10
marc,C,10
marc,C,20
marc,T,30
marc,A,10

我需要对这些值求和并显示名称和结果,但第 2 列需要显示从值 P、A、C 中分离出来的值 T 的总和。 输出应该是这样的:

column$1,column$2,column$3,column$4
john,PCA,40
john,T,40,CORRECT
marc,PCA,50
marc,T,30,INCORRECT

我所能做的就是从原始 csv 中提取我需要的列:

    awk -F "|" '{print $8 "|" $9 "|" $4}' input.csv >> output.csv

也按正确的列排序:

sort -t "|" -k1 input.csv >> output.csv

并在 csv 末尾添加一个新列:

awk -F, '{NF=2}1' OFS="|" input.csv >> output.csv

我设法按列 $1 和 $2 求和并显示总和,但我不知道如何对列 $2 中的不同值进行分组:

awk -F "," '{col[$1,$2]++} END {for(i in col) print i, col[i]}' file > output

【问题讨论】:

  • 试试awk '{if($2 == "T") $4 = "MATCHED" ; print $0}' file > newFile祝你好运。
  • 发布一些简洁、可测试的样本输入和预期输出,我们可以为您提供帮助。
  • 刚刚编辑了问题
  • 是什么决定了文本 ,CORRECT 还是 ,INCORRECT 应该附加到行中?它在您的示例输出中,但在您的问题中没有解释。
  • 对不起。如果 P,C,A 记录的 SUM 与 T 记录的 SUM 匹配,则正确。

标签: linux bash sorting csv awk


【解决方案1】:

假设“正确”和“错误”是通过比较“PCA”值与“T”值来确定的,下面的 awk 脚本应该可以解决问题:

awk -F, -vOFS=, '$2=="T"{t[$1]+=$3;n[$1]} $2!="T"{s[$1]+=$3;n[$1]} END{ for(i in n){print i,"PCA",s[i]; print i,"T",t[i],(t[i]==s[i] ? "CORRECT" : "INCORRECT")} }' inputfile

为了便于阅读,我们将其拆分出来,如下所示:

awk -F, -vOFS=, '

  $2=="T" {    # match all records that are "T"
    t[$1]+=$3  # add the value for this record to an array of totals
    n[$1]      # record this name in our authoritative name list
  }

  $2!="T" {    # match all records that are NOT "T"
    s[$1]+=$3  # add the value for this record to an array of sums
    n[$1]      # record this name too
  }

  END {        # Now that we've collected data, analyse the results
    for (i in n) {  # step through our authoritative list of names
      print i,"PCA",s[i]
      print i,"T",t[i],(t[i]==s[i] ? "CORRECT" : "INCORRECT")
    }
  }

' inputfile

请注意,awk 中不保证数组顺序,因此您的输出可能与输入的顺序不同。

如果您希望使用竖线分隔输出,请将-vOFS=, 更改为-vOFS='|'

然后你可以使用排序:

awk ... | sort

默认为-k1

【讨论】:

  • 做到了!我只需要添加另一个条件来忽略标题,如果记录不是“john”,而是“john p.”,但这正是我所要求的。非常感谢。
  • 快速提问:我现在正在尝试使用 -vOFS='|'但它不起作用......还有另一种定义分升的方法吗?
【解决方案2】:

Awk 是面向流的。它处理输入并输出您更改的内容。它不适用于文件更改。

你只需要添加一个对应的打印

awk '{if($2 == "T") {print "MATCHED"}}'

如果您想输出超过“匹配”的内容,则需要将其添加到打印中 例如'{print $1 "|" $2 "|" $3 "|" " MATCHED"}'

或使用print $0 作为上面的评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2018-10-23
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    相关资源
    最近更新 更多