检查一个文件的所有行是否都包含在另一个文件中

7

我有一个文件:a.txt,每行都有一个数字。我还有另一个文件b.txt,每行也有一个数字。
如何检查文件a.txt的所有行是否都包含在b.txt中?


最好附加示例输入/输出 ;) - Gilles Quénot
需要检查行号吗? - Малъ Скрылевъ
实际上是同一个问题http://stackoverflow.com/questions/27376807/difference-of-files-from-nth-line/27377665#27377665 - user3442743
@user3442743:那个问题指定使用sed或awk;这个更通用。 - user1071847
相关内容:https://unix.stackexchange.com/questions/397747/check-whether-all-lines-of-file-occur-in-different-file - Ciro Santilli OurBigBook.com
7个回答

6
你可以使用comm来完成这个任务。
如果a.txtb.txt已经按字典序升序排序,你只需要:
comm -23 a.txt b.txt

或者也许。
comm -23 a.txt b.txt | wc -l

如果没有输出(或者wc -l返回“0”),那么a.txt文件中的每一行都在b.txt中(-2禁止输出只存在于b.txt的行,-3禁止输出两个文件都有的行)。
如果文件未排序,您可以使用进程替换将每个文件的排序输出传递给comm
comm -23 <(sort a.txt) <(sort b.txt)

该进程替换<(COMMAND)COMMAND的输出放入FIFO或/dev/fd中的文件(取决于系统支持什么)。在命令行上,<(COMMAND)会作为命令行扩展的一部分被替换为此文件的名称。
这确实检查线路,因此如果数字在a.txt中存在两次,但在b.txt中只存在一次,则输出来自a.txt的重复行。如果您不关心重复项,请使用sort -u FILE而不是sort FILE(或者在您的sort没有唯一排序开关的情况下使用sort FILE | uniq

3
您可以使用diff命令来比较两个文件。 示例用法
$ seq 1 5 > a.txt
$ seq 1 5 > b.txt
$ diff a.txt b.txt
$
$ seq 1 6 > b.txt
$ diff a.txt b.txt
5a6
> 6

编辑

你也可以尝试类似以下的方法:

$ seq 1 5 > a.txt
$ seq 1 5 > b.txt
$ diff a.txt b.txt > /dev/null  && echo files are same || echo files are not same
files are same
$ seq 1 6 > b.txt
$ diff a.txt b.txt > /dev/null  && echo files are same || echo files are not same
files are not same

但是为了达到这个目的,两个文件中数字的顺序必须相同,对吧? - mrtubis
@mrtubis 是的,它需要这样做。因为它会将两个文件中相应行进行比较。你可以对这两个文件进行排序以确保准确性。 - nu11p01n73R
@nu11p01n73R:对于小文件来说那个方法是行得通的。但如果文件有2000行,我怎么从差异中知道它是一个子集呢? - Jim
@Jim 如果这两个文件相同,那么diff命令不会输出任何内容。但是如果有差异,它会显示出来。 - nu11p01n73R
@Jim,我已经编辑了我的答案,以便在有差异时输出“echo”。希望能对你有所帮助。 - nu11p01n73R
编辑无法工作,因为a.txt包含在b.txt中,但它们并不相等。 - jinawee

1

Try this :

awk '
    NR==FNR{arr[$0]++;next}
    {print ($0 in arr) ? $0 " in both files" : $0 " *not* in both files"}
' b.txt a.txt

带有的内容:

 $ diff -a b.txt a.txt
2c2
< 3
---
> 2
6d5
< 7

1
如果数字在每个文件中都是唯一的(没有重复),您可以将它们连接起来,然后使用管道传递给sort和uniq,并检查有多少行。
例如:
>> cat a.txt
1
2
8
5
>> cat b.txt
1
2
5
3
8
>> cat a.txt b.txt | sort | uniq | wc -l
5

由于答案与b.txt中的行数相同,所以答案是肯定的!


0
awk 'FNR==NR{b[$0];next}
            {if($0 in b){print $0" is present in b.txt"}
             else{print $0" is not present in b.txt"}
            }' b.txt a.txt

如果有多个相同的数字,这可能会导致误导性的结果。 - user3442743

0
一个Perl的解决方案:
#!/usr/bin/perl
use strict;
use warnings;
use List::Compare;
#read file a.txt
open (my $fh, "<", "a.txt") or die $!;
while (<$fh>){
    push @atxt = $_;
}
close($fh); 
#read file b.txt
open (my $fh2, "<", "b.txt") or die $!;
while (<$fh2>){
    push @btxt = $_;
} 
close($fh2);

my $lc = List::Compare->new(\@atxt, \@btxt);

print $lc->get_intersection;
print $lc->get_union;
print $lc->get_unique;
print $lc->get_complement;

还有许多其他选项,请查看文档:http://search.cpan.org/~jkeenan/List-Compare-0.39/lib/List/Compare.pm


0
一个包含另一个文件的文件意味着a.txt的整个内容以相同的顺序(包括可能的重复)存在于b.txt中,而你最后的问题:“如何检查文件a.txt中的所有行是否都包含在b.txt中?”则意味着顺序和重复无关紧要。这是一个简单的例子:
a.txt:

5
7
3

b.txt:

9
5
3
7

这个解决方案可以满足你引用的问题,但不能解决标题中的问题。

如果容器文件不是很大(否则你会遇到像我下面演示的直接方法所遇到的内存问题),那么解决引用的问题会更加容易。一个简单的解决方案是创建一个包含b.txt中所有数字的集合,然后遍历a.txt,如果在构建的集合中找不到某个项,则返回false。如果在遍历完a.txt的内容之前没有发生这种情况,则返回true。

这在伪代码中如下所示:

ContentSet = {}
for each element b of b.txt
    add b into ContentSet

for each element a of a.txt
    if a is not in ContentSet then return false

return true

这种方法的优点在于第一次迭代可以消除容器文件中可能存在的重复项,从而将文件大小和搜索时间保持在最小限度,并且如果集合具有良好的哈希实现,则可以比朴素方法更快地运行第二次迭代,因为检查哈希集是否包含给定对象是一个O(1)操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接