【问题标题】:3 file string matching pattern awk in tab separated file3 制表符分隔文件中的文件字符串匹配模式 awk
【发布时间】:2018-11-24 01:40:07
【问题描述】:

我有 3 个文件:

文件 1

NODE_2020   Cancer
NODE_2029   Thug
NODE_0902   Snap

文件 2

NODE_2020   Mikro   
NODE_2029   Bold
NODE_0902   Mini

文件 3

NODE_2020   Gold
NODE_2080   Damn
NODE_0900   Gueo

我需要在其他两个中搜索文件 1 的第一列:如果值匹配,则 文件 2 的第 2 列文件 3 的第 2 列 将打印成一个文件;如果不是,则将打印一个“NO MATCH”字符串作为回报。输出文件将是这样的:

Query   File1   File2   File3

NODE_2020   Cancer  Mikro   Gold    
NODE_2029   Thug    Bold    NO MATCH    
NODE_0902   Snap    Mini    NO MATCH

非常感谢 Awk/sed/perl 解决方案。我坚持做的是使用文件 1 的第一列作为变量,仅使用 if 语句查看其他 2 个文件。

这是我尝试过的,使用文件 1 中的列并匹配到文件 2:

awk 'NR==FNR{a[NR]=$1;next} { print a[FNR],"\t", $2 }' file1 file2

它实际上适用于 2 个文件。不知道如何扩展到三个文件,并添加“NO MATCH”模式。

【问题讨论】:

  • 请不要在 7 分钟内投反对票。给我一个合理的时间来发布您的要求。
  • 你为什么不使用你提到的副本中的一种解决方案?
  • 因为我找不到在 awk 中添加 if 语句以打印“NO MATCH”项并将此比较扩展到三个文件的方法。这主要是因为 awk 的答案通常只是代码,完全没有描述。
  • awk 答案通常只是代码,因为它们通常是清晰、简单且简单易懂的,只要浏览一下文档即可。

标签: bash perl text awk sed


【解决方案1】:

使用 GNU awk 实现真正的多维数组和 ARGIND:

$ cat tst.awk
BEGIN { OFS="\t" }
(NR==FNR) || ($1 in vals) {
    vals[$1][ARGIND] = $2
}
END {
    printf "%s%s", "Query", OFS
    for (fileNr=1; fileNr<=ARGIND; fileNr++) {
        printf "%s%s", ARGV[fileNr], (fileNr<ARGIND ? OFS : ORS)
    }
    for (key in vals) {
        printf "%s%s", key, OFS
        for (fileNr=1; fileNr<=ARGIND; fileNr++) {
            val = (fileNr in vals[key] ? vals[key][fileNr] : "NO MATCH")
            printf "%s%s", val, (fileNr<ARGIND ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file1 file2 file3
Query   file1   file2   file3
NODE_2020       Cancer  Mikro   Gold
NODE_0902       Snap    Mini    NO MATCH
NODE_2029       Thug    Bold    NO MATCH

【讨论】:

  • 感谢您的回答。你能解释一下什么是 valsARGIND 吗?
  • 像魅力一样工作。非常感谢
  • 不客气。 vals 是一个输入值数组,类似于代码中的aARGIND 在文档中明确定义为当前输入文件号,请参阅gnu.org/software/gawk/manual/gawk.html。这个答案和@anubhava 的 btw 之间的区别在于,这将适用于任意数量的输入文件,而不仅仅是 3 个,并且使用文件名作为列标题而不是对它们进行硬编码。要学习 awk,我强烈建议您阅读 Arnold Robbins 的《Effective Awk Programming, 4th Edition》一书。
【解决方案2】:

你可以使用这个awk:

awk -v OFS='\t' 'function bval(p,q) {
    return ((p,q) in b ? b[p,q] : "NO MATCH")
}
FNR == NR {
   a[$1] = $2
   next
}
{
   b[FILENAME,$1] = $2
}
END {
   print "Query", ARGV[1], ARGV[2], ARGV[3]
   for (i in a)
      print i, a[i], bval(ARGV[2],i), bval(ARGV[3],i)
}' file{1,2,3}

Query   file1   file2   file3
NODE_2020   Cancer  Mikro   Gold
NODE_0902   Snap    Mini    NO MATCH
NODE_2029   Thug    Bold    NO MATCH

【讨论】:

  • 是的,你是对的,因为 ARGIND 被打印为空。但是我已经编辑了这个 awk 以摆脱 ARGIND 以使其在 BSD 或任何其他较旧的 awk 上工作。
猜你喜欢
  • 1970-01-01
  • 2017-10-19
  • 2016-08-28
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
相关资源
最近更新 更多