如果两个文件中第一列的内容在Unix中匹配,则打印两个文件的列

时间:2017-05-26 02:00:47

标签: bash shell unix awk gawk

我有两个文件,如下所示

file1
name|address office
AK|Victoria Street
BK|Admond Street
DK|Business Street

file2
name|address home
AK|Nilofer Villa
ck|Bluewaters
bk|Homingo Apartment

命令或代码行应该比较两个文件的第一列并将列合并为name|address office|address home,并在不匹配的地方替换NA,文件的内容可能很大。完整输出应如下

file3
name|address office|address home
AK|Victoria Street |Nilofer Villa
BK|Admond Street|Homingo Apartment
DK|Business Street|NA
CK|NA|Bluewaters

这是我到目前为止所尝试的内容:

awk -F '|' 'NR==FNR{c[$1]++;next};c[$1] > 0' file1 file2

但上面的代码行没有合并,只是根据列名生成输出差异。这个案例太敏感了 name|address home AK|Nilofer Villa

请帮助,也检查了几个问题,但没有解决我的目的。

2 个答案:

答案 0 :(得分:4)

您可以使用join命令执行此操作:

$ join -a 1 -a 2 -e NA -o '0,1.2,2.2' -t '|' -i <(sort f1) <(sort f2)
AK|Victoria Street|Nilofer Villa
BK|Admond Street|Homingo Apartment
ck|NA|Bluewaters
DK|Business Street|NA
name|address office|address home

其中:

  • -a 1-a 2包含来自任一文件的未加入的行。
  • -e-o一起展示“NA”字段。手册页未提及此内容,但要使用-e,您必须指定-o。我们只按以下顺序显示字段:连接列,第一个文件的第二列,第二个文件的第二列。
  • -t设置分隔符

当然我们还必须在使用join之前对文件进行排序(这是必需的),因此我们使用进程替换。如果你的shell没有,你可以使用临时文件。

答案 1 :(得分:2)

$ cat tst.awk
BEGIN { FS=OFS="|" }
{
    name = (FNR>1 ? toupper($1) : $1)
    if (!seen[name]++) {
        names[++numNames] = name
        vals[name,1] = vals[name,2] = "NA"
    }
    vals[name,ARGIND] = $2
}
END {
    for (nameNr=1; nameNr<=numNames; nameNr++) {
        name = names[nameNr]
        print name, vals[name,1], vals[name,2]
    }
}

$ awk -f tst.awk file1 file2
name|address office|address home
AK|Victoria Street|Nilofer Villa
BK|Admond Street|Homingo Apartment
DK|Business Street|NA
CK|NA|Bluewaters

以上使用GNU awk进行ARGIND,其他awk只是在脚本开头添加FNR==1{ARGIND++}