使用 awk 比较两个文件并映射聚合的多个值

Luk*_*sCB 0 csv awk loops

我有两个文件需要比较和映射多行匹配的值。

我的映射文件 ( map.csv) 看起来像:

id,name
123,Hans
123,Britta
232,Peter
343,Siggi
343,Horst
Run Code Online (Sandbox Code Playgroud)

数据文件 ( data.csv) 是

contact,id,names
m@a.de,123,
ad@23.com,343,
adf@er.org,123,
af@go.er,232,
llk@fh.com,343,
ad@wer.org,789,
Run Code Online (Sandbox Code Playgroud)

不想要的输出应该是这样的

contact,id,names
m@a.de,123,Hans Britta 
ad@23.com,343,Siggi Horst 
adf@er.org,123,Hans Britta 
af@go.er,232,Peter 
llk@fh.com,343,Siggi Horst
ad@wer.org,789,NO ENTRY
Run Code Online (Sandbox Code Playgroud)

映射文件中的一个 ID 有多个值,它们应该以空格分隔打印到names数据文件的列中。如果映射文件中没有 ID,则应打印“NO ENTRY”。

这是 awk 命令

awk 'NR==FNR{a[$1];next}{print $0,($2 in a)? a[$2]:"NO ENTRY"}' map.csv data.csv
Run Code Online (Sandbox Code Playgroud)

我显然失败了,因为我不知道如何遍历映射文件以将多个值获取到一个 id(或当前任何值)。

Rav*_*h13 5

使用您显示的样本,请尝试以下操作。

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  arr[$1]=(arr[$1]?arr[$1] " ":"")$2
  next
}
FNR==1{
  print
  next
}
{
  sub(/,$/,"")
  print $0,($2 in arr)?arr[$2]:"NO ENTRY"
}
' map.csv data.csv
Run Code Online (Sandbox Code Playgroud)

说明:为以上添加详细说明。

awk '                                 ##Starting awk program from here.
BEGIN{                                ##Starting BEGIN section of this program from here.
  FS=OFS=","                          ##Setting FS and OFS as comma here.
}
FNR==NR{                              ##Checking condition which will be TRUE when map.csv is being read.
  arr[$1]=(arr[$1]?arr[$1] " ":"")$2  ##Creating arr with index of $1 and which has value of $2 and keep concatenating its value with same index.
  next                                ##next will skip all further statements from here.
}
FNR==1{                               ##Checking condition if this is first line of data.csv then do following.
  print                               ##Printing current line here.
  next                                ##next will skip all further statements from here.
}
{
  sub(/,$/,"")                        ##Substituting last comma with NULL here.
  print $0,($2 in arr)?arr[$2]:"NO ENTRY"  ##Printing current line and printing either value of arr with index of $2 OR printing NO ENTRY as per requirement.
}
' map.csv data.csv                    ##Mentioning Input_file names here.
Run Code Online (Sandbox Code Playgroud)


Dav*_*ica 5

您可以在您的情况下使用两个规则。一个从其中捕获数据map.csv,然后第二个规则输出结果,例如

(编辑 - 更新以完全匹配第一行输出)

awk -F, '
    NR==FNR { if (FNR > 1) a[$1]=a[$1]" "$2; next }
    FNR==1  { print; next }
            { printf "%s,%s,%s\n", $1, $2, a[$2]?a[$2]:"NO ENTRY" }
' map.csv data.csv
Run Code Online (Sandbox Code Playgroud)

第一条规则由NR=FNR(当前记录号等于文件记录号——例如第一个文件)限定。第二个规则只在第二个文件上运行,并在输出聚合数据之前输出标题行不变。

示例使用/输出

你可以简单地选择,复制和上面的命令中间的鼠标粘贴到当前目录保持一个xtermmap.csvdata.csv其结果如下:

awk -F, '
    NR==FNR { if (FNR > 1) a[$1]=a[$1]" "$2; next }
    FNR==1  { print; next }
            { printf "%s,%s,%s\n", $1, $2, a[$2]?a[$2]:"NO ENTRY" }
' map.csv data.csv
Run Code Online (Sandbox Code Playgroud)

选择

另一种做完全相同的事情,但通过OFS=","在输出开始之前显式设置允许使用print而不是简化(稍微)简化printf是:

awk -F, '
    NR==FNR { if (FNR > 1) a[$1]=a[$1]" "$2; next }
    FNR==1  { OFS=","; print; next }
            { print $1, $2, a[$2]?a[$2]:"NO ENTRY" }
' map.csv data.csv
Run Code Online (Sandbox Code Playgroud)

(相同的输出)