比较 bash 中两个文件中除最后 N 列以外的所有列

Compare all but last N Columns across two files in bash

我有 2 个文件:一个有 18 列;另一个有更多。我需要仅在前 18 列中找到不匹配的行,而忽略其他文件中的其余部分。但是,我需要保留并打印整行(剪切不起作用)。

文件 1:

F1 F2 F3....F18
A  B  C.... Y
AA BB CC... YY

文件 2:

F1 F2 F3... F18... F32
AA BB CC... YY... 123
AAA BBB CCC... YYY...321

输出不在文件 1 中:

AAA BBB CCC YYY...321

输出不在文件 2 中:

 A  B  C...Y

如果可能的话,我希望尽可能少地使用 diff 或 awk。

你可以使用 awk:

awk '{k=""; for(i=1; i<=18; i++) k=k SUBSEP $i} FNR==NR{a[k]; next} !(k in a)' file1 file2
  • 对于两个文件中的每一行,我们首先通过连接前 18 个字段
  • 创建一个键
  • 然后我们在迭代第一个文件时将此键存储在关联数组中
  • 最后,当在我们的关联数组中找不到这个新键值时,我们打印第二个文件的每一行。

你可以使用 grep:

grep -vf file1 file2
grep -vf <(cut -d" "  -f1-18 file2) file1

要获得两个文件之间的设置差异,您只需要一点点,类似于@anubhava 的回答

$ awk 'NR==FNR{f1[[=10=]]; next}  
              {k=; for(i=2;i<=18;i++) k=k FS $i; 
               if(k in f1) delete f1[k]; 
               else f2[[=10=]]} 
           END{print "not in f1"; 
               for(k in f2) print k; 
               print "\nnot in f2"; 
               for(k in f1) print k}' file1 file2

可以重写以保留 file2

中的顺序
$ awk 'NR==FNR{f1[[=11=]]; next}  
               {k=; for(i=2;i<=18;i++) k=k FS $i; 
                if(k in f1) delete f1[k]; 
                else {if(!p) print "not in f1";  
                      f2[[=11=]]; print; p=1}} 
            END{print "\nnot in f2"; 
                for(k in f1) print k}' file1 file2