【问题标题】:awk to improve command print Match and Non-Match case:awk 改进命令打印匹配和非匹配情况:
【发布时间】:2014-08-13 21:59:57
【问题描述】:

想从两个文件中读取并比较第一个字段然后打印

  1. 两个文件中的匹配行 -(在 f11.txt 和 f22.txt 中可用)-> Op_Match.txt
  2. f11.txt 中的不匹配行(在 f11.txt 中可用,在 f22.txt 中不可用)-> Op_NonMatch_f11.txt
  3. f22.txt 中的不匹配行(在 f22.txt 中可用,在 f11.txt 中不可用)-> Op_NonMatch_f22.txt

使用以下 3 个单独的命令来实现上述场景的 .

f11.txt

10,03-APR-14,abc
20,02-JUL-13,def
10,19-FEB-14,abc
20,02-AUG-13,def
10,22-JAN-07,abc
10,29-JUN-07,abc
40,11-SEP-13,ghi

f22.txt

50,DL,3000~4332,ABC~XYZ
10,DL,5000~2503,ABC~XYZ
30,AL,2000~2800,DEF~PQZ

要匹配两个文件中的行:

awk ' BEGIN {FS = OFS = ","} FNR==NR {a[$1] = $0; next} ($1 in a) {print $0,a[$1]}'   f22.txt f11.txt> Op_Match.txt

10,03-APR-14,abc,10,DL,5000~2503,ABC~XYZ
10,19-FEB-14,abc,10,DL,5000~2503,ABC~XYZ
10,22-JAN-07,abc,10,DL,5000~2503,ABC~XYZ
10,29-JUN-07,abc,10,DL,5000~2503,ABC~XYZ

到 f11.txt 中的非匹配行:

awk ' BEGIN {FS = OFS = ","} FNR==NR {a[$1] = $0; next} !($1 in a) {print $0}'   f22.txt f11.txt > Op_NonMatch_f11.txt

20,02-JUL-13,def
20,02-AUG-13,def
40,11-SEP-13,ghi

到 f22.txt 中的非匹配行:

awk ' BEGIN {FS = OFS = ","} FNR==NR {a[$1] = $0; next} !($1 in a) {print $0}'   f11.txt f22.txt > Op_NonMatch_f22.txt

50,DL,3000~4332,ABC~XYZ
30,AL,2000~2800,DEF~PQZ

使用上述 3 个单独的命令来实现上述场景。有没有最简单的方法来避免 3 个不同的命令?任何建议...!!!

【问题讨论】:

标签: awk


【解决方案1】:

类似这样的东西,未经测试:

awk '
BEGIN{ FS=OFS="," }
NR==FNR {
    fname1 = FILENAME
    keys[NR] = $1
    recs[NR] = $0
    key2nrs[$1] = ($1 in key2nrs ? key2nrs[$1] RS : "") NR
    next
}
{
    if ($1 in key2nrs) {
        split (key2nrs[$1],nrs,RS)
        for (i=1; i in nrs; i++) {
            print recs[nrs[i]], $0 > "Op_Match.txt"
        }
        matched[$1]
    }
    else {
        print > ("Op_NonMatch_" FILENAME ".txt")
    }
}
END {
    for (i=1; i in recs; i++) {
        if (! (keys[i] in matched) ) {
            print recs[i] > ("Op_NonMatch_" fname1 ".txt")
        }
    }
}
' f11.txt f22.txt

此答案与 Kent 和 Etans 答案之间的主要区别在于,他们假设 f22.txt 中的 $1 只能在该文件中出现一次,而如果 10 出现在多个f22.txt 行。

另一个区别是,上面将按照它们在输入文件中出现的顺序输出行,而其他答案将根据它们在内部存储在哈希表中的方式以随机顺序输出其中一些。

【讨论】:

  • 在我看到 OP 的代码之前,我也想到了那个问号(如果 F22 可以有 dup 行)
  • 直到我看到你的回答,我才想到 f22.txt 中可能没有重复的键值。
  • 我和肯特在一起。我只是假设 OP 的条件是正确的。
  • 你可能是对的。 OP 发布的脚本通常是错误的,但如果是这种情况,请在此处确认。
  • Ed Morton:哇,这是岩石,它正在按预期的方式工作,非常感谢您的大力支持!!!
【解决方案2】:

我没有检查过@EdMorton 的答案,但他很可能已经猜对了。

我的解决方案(乍一看似乎比他略逊一筹)是:

awk -F, '
FNR==NR {
    a[$1]=$0;
    next
}
($1 in a){
    print $0,a[$1] > "Op_Match.txt"
    am[$1]++
}
!($1 in a) {
    print $0 > "Op_NonMatch_f11.txt"
}
END {
    for (i in a) {
        if (!(i in am)) {
            print a[i] > "Op_NonMatch_f22.txt"
        }
    }
}
' f22.txt f11.txt

【讨论】:

  • 如果 OP 在 f22 中不能有 dup 键值并且不关心 END 部分中的行输出顺序,那么您和 Kents 的解决方案就可以正常工作。
【解决方案3】:

这是一个:

awk -F, -v OFS="," 'NR==FNR{a[$1]=$0;next}
    $1 in a{print $0,a[$1]>("common.txt");c[$1];next} 
    {print $0>("NonMatchFromFile1.txt")}                     
    END{for(x in a)
        if(!(x in c)) 
            print a[x]>("NonMatchFromFile2.txt")}' f2 f1     

这样,您将获得 3 个文件:common.txt, nonmatchfromFile1.txt and nonMatchfromfile2.txt

【讨论】:

  • 我认为您的 c[$1] 人口在错误的位置。您不需要代表输出文件的字符串周围的括号 - 当您在那里构建文件名时,您只需要括号,例如通过串联。
  • @EdMorton 是的,你是对的,来自一个糟糕的编辑,我现在就修复它