Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 快速查找一个文件中不在另一个文件中的行的方法?_Bash_Grep_Find_Diff - Fatal编程技术网

Bash 快速查找一个文件中不在另一个文件中的行的方法?

Bash 快速查找一个文件中不在另一个文件中的行的方法?,bash,grep,find,diff,Bash,Grep,Find,Diff,我有两个大文件(文件名集)。每个文件中大约有30000行。我试图找到一种快速的方法来查找文件1中不在文件2中的行 例如,如果这是file1: line1 line2 line3 line1 line4 line5 这是file2: line1 line2 line3 line1 line4 line5 那么我的结果/输出应该是: line2 line3 这项工作: grep-v-f文件2文件1 但在我的大文件上使用时,速度非常非常慢 我怀疑使用diff()有一个很好的方法来实现这一点,

我有两个大文件(文件名集)。每个文件中大约有30000行。我试图找到一种快速的方法来查找文件1中不在文件2中的行

例如,如果这是file1:

line1
line2
line3
line1
line4
line5
这是file2:

line1
line2
line3
line1
line4
line5
那么我的结果/输出应该是:

line2
line3
这项工作:

grep-v-f文件2文件1

但在我的大文件上使用时,速度非常非常慢

我怀疑使用
diff()
有一个很好的方法来实现这一点,但是输出应该是行,而不是其他,我似乎找不到一个开关来实现这一点

有谁能帮我找到一种快速的方法,使用bash和基本Linux二进制文件

编辑:为了跟进我自己的问题,这是迄今为止我使用
diff()
找到的最好方法:


当然,一定有更好的方法吗?

排序和差异的速度是多少

sort file1 -u > file1.sorted
sort file2 -u > file2.sorted
diff file1.sorted file2.sorted

使用fgrep或向grep添加-F选项可能会有所帮助。但为了更快的计算,您可以使用Awk

您可以尝试以下Awk方法之一:


您可以通过控制GNU
diff
输出中旧/新/未更改行的格式来实现这一点:

diff --new-line-format="" --unchanged-line-format=""  file1 file2
应该对输入文件进行排序以使其正常工作。使用
bash
(和
zsh
),您可以使用进程替换进行适当排序

如果某些行中有空格,则
-t
确保它比较整行。

该命令(common的缩写)可能有用
comm-逐行比较两个排序的文件

#find lines only in file1
comm -23 file1 file2 

#find lines only in file2
comm -13 file1 file2 

#find lines common to both files
comm -12 file1 file2 

man
文件实际上对此非常可读。

就像konsolebox建议的那样,海报grep解决方案

grep -v -f file2 file1
如果您只需添加
-F
选项,将模式视为固定字符串而不是正则表达式,实际上效果非常好(快速)。我在一对约1000行的文件列表上验证了这一点,我必须进行比较。将grep输出重定向到
wc-l
时,使用
-F
需要0.031s(实数),而不使用它需要2.278s(实数)

这些测试还包括
-x
开关,这是解决方案的必要部分,以确保在file2包含与file1中的一行或多行部分(而不是全部)匹配的行时完全准确

因此,不需要对输入进行排序、快速、灵活(区分大小写等)的解决方案是:

这并不适用于所有版本的grep,例如,它在macOS中失败,其中文件1中的一行将显示为不存在于文件2中,即使它存在,如果它与作为它的子字符串的另一行匹配。或者,为了使用此解决方案,您可以使用Python:

python -c '
lines_to_remove = set()
with open("file2", "r") as f:
    for line in f.readlines():
        lines_to_remove.add(line.strip())

with open("f1", "r") as f:
    for line in f.readlines():
        if line.strip() not in lines_to_remove:
            print(line.strip())
'

我通常使用的方法是使用
--suppress common lines
标志,不过请注意,这仅在以并排格式执行时才有效


diff-y--suppress common lines file1.txt file2.txt

我发现使用正常的if和for循环语句非常有效

for i in $(cat file2);do if [ $(grep -i $i file1) ];then echo "$i found" >>Matching_lines.txt;else echo "$i missing" >>missing_lines.txt ;fi;done
如果您缺少“奇特的工具”,例如在一些最小的Linux发行版中,有一种解决方案,它只使用
cat
sort
uniq

cat includes.txt excludes.txt excludes.txt | sort | uniq --unique
测试:


moreutils
包中的
grep

使用
combine
相比,这也是相对较快的,这是一个支持
not
xor
操作的集合实用程序

combine file1 not file2
i、 e给我文件1中的行,但不在文件2中

或者给我文件1中的行减去文件2中的行

注意:
合并
在执行任何操作之前,在两个文件中排序并查找唯一的行,但
diff
不会。因此,您可能会发现
diff
combine
的输出之间的差异

所以实际上你是说

在file1和file2中找到不同的行,然后给我file1中的行减去file2中的行


根据我的经验,它比其他选项快得多

这对我来说似乎很快:

comm -1 -3 <(sort file1.txt) <(sort file2.txt) > output.txt

comm-1-3如果速度更快,您可以试试这个:
awk'NR==FNR{a[$0];next}!(a)'file2 file1>out.txt($0 in a)
无快速要求:感谢您告诉我grep-v-f file2 file1另请参见:。简化工具集的简单方法:
cat file1 file2 file2 | sort | uniq--uniq--unique
,请参见下面我的答案。这正是我所需要的,只需要巨大的grep占用的一小部分时间。谢谢发现这一点我们中的一些人不在gnu上[OS X bsd here…]:)我想你是指
diff
:通常输入文件会不同,在这种情况下,
diff
返回1。认为这是一种奖励;如果您在shell脚本中进行测试,0和1应该是退出代码,2表示有问题。@mr.spuratic啊,是的,现在我在
man diff
中找到了它。谢谢感谢您提醒我在进行差异排序之前需要对文件进行排序。排序+差异快得多。一行;-)diff+1这是唯一不需要对输入进行排序的答案。虽然OP显然对这一要求感到满意,但在许多现实场景中,这是一个不可接受的约束。在OSX上可以完美地工作。排序输入的要求可能应该突出显示。
comm
还可以选择验证输入是否已排序,
——检查顺序
(它似乎无论如何都会这样做,但此选项将导致它出错,而不是继续)。但要对文件进行排序,只需执行以下操作:
com-23我将在Windows中生成的文件与在Linux中生成的文件进行了比较,结果发现
comm
根本不起作用。我花了一段时间才弄明白这与行的结尾有关:即使看起来相同的行如果不同,也会被视为不同nt行尾。命令
dos2unix
可用于将CRLF行尾仅转换为LF。是的,它可以工作,但即使在
for i in $(cat file2);do if [ $(grep -i $i file1) ];then echo "$i found" >>Matching_lines.txt;else echo "$i missing" >>missing_lines.txt ;fi;done
cat includes.txt excludes.txt excludes.txt | sort | uniq --unique
seq 1 1 7 | sort --random-sort > includes.txt
seq 3 1 9 | sort --random-sort > excludes.txt
cat includes.txt excludes.txt excludes.txt | sort | uniq --unique

# Output:
1
2    
combine file1 not file2
comm -1 -3 <(sort file1.txt) <(sort file2.txt) > output.txt