有没有什么工具可以获取文件A包含但文件B不包含的行?我可以使用例如perl编写一些简单的脚本,但是如果已经存在类似的脚本,那么从现在开始我将节省时间。

评论

请参阅“stackoverflow.com/questions/5812756/…”

stackoverflow.com/questions/4366533/…

#1 楼

是。用于在文件中搜索文本字符串的标准grep工具可用于将一个文件中的所有行从另一个文件中减去。

grep -F -x -v -f fileB fileA


这通过将fileB中的每一行用作一个模式(-f fileB)并将其视为要匹配的普通字符串(不是常规正则表达式)(-F)。您强制匹配发生在整行(-x)上,并仅打印不匹配的行(-v)。因此,您要打印出fileA中不包含与fileB中任何行相同数据的行。

该解决方案的缺点是,它不考虑行顺序,并且输入在不同位置有重复的行,您可能无法获得预期的结果。解决方案是使用真正的比较工具,例如diff。您可以通过创建一个diff文件,使上下文值位于文件中100%的行中,然后将其解析为仅将文件A转换为文件B时要删除的行。(请注意,此命令还删除了diff得到正确的行后进行格式化。)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC


评论


@ inderpreet99小写的-u参数实际上接受带数字的参数,只要它后面没有空格即可。我以前使用它的方式的优点是它可以使用或不使用值,因此您可以在该子命令例程中使用一些不返回任何值的东西。另一方面,大写字母“ -U”需要一个参数。

–卡莱布
13年8月27日在21:46

小心,grep -f是O(N ^ 2)我相信:stackoverflow.com/questions/4780203 / ...

–rogerdpack
2015年10月16日17:33

diff管道工作谢谢。

–Felipe Alvarez
16年11月3日在23:01

为了解决排序问题,您可以根据需要在命令中使用进程替换来处理grep之前的每个文件。示例:grep -F -x -v -f <(排序文件B)<(排序文件A)

–托尼·切萨罗(Tony Cesaro)
17-10-4在15:22



@TonyCesaro如果您的数据集不是特定于订单的并且不需要考虑重复项,那将起作用。使用diff的优点是考虑了文件中的位置。

–卡莱布
17-10-5在6:06

#2 楼

答案很大程度上取决于您要比较的文件的类型和格式。

如果您要比较的文件是已排序的文本文件,那么Richard Stallman和Davide McKenzie编写的名为comm的GNU工具可能会执行您要执行的过滤。它是coreutils的一部分。

示例

假设您拥有以下2个文件:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6


文件b中的行不在文件a中:

$ comm <(sort a) <(sort b) -3
    6


评论


+1提及通讯;不幸的是,通讯需要排序的文件

–Arcege
2012年2月21日在4:04

这样排序吗? comm <(排序a)<(排序b)-1 -2

– Sirex
2012年2月21日在8:17

这是一些奇怪的语法。 <()?它有效,我明白了,但是这种怪异有什么名字吗?

– mlissner
17年4月5日在22:47

@mlissner <()也称为进程替换。

– miku
17年4月13日在15:51

comm最初由Bell Labs的某人而不是rms于1973年撰写。您指的是后来出现的GNU实现。多年来,Unix实用程序有许多不同的实现。

–StéphaneChazelas
17-10-30在8:33

#3 楼

来自stackoverflow ...


comm -23 file1 file2


-23禁止显示file2(-2)中的行和出现的行在两个(-3)中,仅保留file1中的唯一行。必须对文件进行排序(在您的示例中),如果没有排序,请先通过排序将它们通过管道传输。

请参见此处的手册页

-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)


评论


由于某种原因,这对我不起作用...

– Jan
18年2月7日在21:05

@Jan文件已排序?您如何对它们进行排序?

– JJS
18年2月8日在19:03

@roaima我还有其他答案未提供的其他解释。另外,我要添加-2,而它们仅使用-3,因此并不完全相同。

– JJS
20 Mar 2 '20 at 12:55

@roaima感谢您指出我可以通过从其他类似答案中脱颖而出来改善自己的答案!

– JJS
20 Mar 2 '20 at 18:28

#4 楼

grep和comm(带有sort)方法在大文件上花费很长时间。 SiegeX和ghostdog74共享了两种很棒的awk方法,用于在堆栈溢出中提取两个文件之一唯一的行:

$ awk 'FNR==NR{a[q4312078q]++}FNR!=NR && !a[q4312078q]{print}' file1 file2

$ awk 'FNR==NR{a[q4312078q]++;next}(!(q4312078q in a))' file1 file2


评论


如果要对大文件执行此操作,则将大文件加载到关联数组中的内存限制将是禁止的。

–查尔斯·达菲(Charles Duffy)
16年6月17日在14:01

#5 楼

如果文件很大,而您的条目没有自定义顺序,则grep花费的时间太长。一种快速的替代方法是

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'


[file2-file1结果到屏幕,管道到文件等。]

>更改为<相反的减法。 rm 1 2

#6 楼

您也可以考虑使用vimdiff,它突出显示了vim编辑器中文件之间的差异

评论


但是,有没有一种简单的方法可以自动在Vimdiff中进行减法?

–卡扎尔克
13年3月14日在17:38

#7 楼

来自moreutils软件包的combine非常直观:
combine fileA not fileB

不需要对文件进行排序并保留顺序。
还有xororand运算符。

#8 楼

    awk 'NR==FNR{a[];next}!( in a){print }' fileA fileB

  

     cat fileA
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
  file B
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
    
    output
    
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19


    It will print contents of fileB which is not in fileA


评论


请让我知道拒绝投票的原因

– Praveen Kumar BS
20-10-14在13:44

您要$ 0,而不是$ 1。而且,这基本上与Miles的答案相同。

–Quasímodo
20-10-19在15:37