当前位置: 首页 > 面试题库 >

从Bash中另一个更大的文件中查找文件行的最快方法

乐钱青
2023-03-14
问题内容

我有两个文件,file1.txtfile2.txtfile1.txt有大约14000条线,file2.txt大约有20亿条线。
每行file1.txt有一个字段f1,而file2.txt有3个字段,f1通过f3,以分隔|

我想从中找到匹配项的所有行(或者,如果我们不想花费额外的时间来拆分的值,则可以找到行file2.txtf1的任何行)。file1.txt``f2``file2.txt``file2.txt

file1.txt(大约14000行, 未排序 ):

foo1
foo2
...
bar1
bar2
...

file2.txt(大约20亿行, 未排序 ):

date1|foo1|number1
date2|foo2|number2
...
date1|bar1|number1
date2|bar2|number2
...

预期输出:

date1|foo1|number1
date2|foo2|number2
...
date1|bar1|number1
date2|bar2|number2
...

这是我尝试过的,似乎要花几个小时才能运行:

fgrep -F -f file1.txt file2.txt > file.matched

我想知道是否有更好,更快的方法来执行常见的Unix命令或小的脚本。


问题答案:

一小段Perl代码解决了该问题。这是采取的方法:

  • 将的行存储file1.txt在哈希中
  • file2.txt逐行读取,解析并提取第二个字段
  • 检查提取的字段是否在哈希中;如果是这样,打印行

这是代码:

#!/usr/bin/perl -w

use strict;
if (scalar(@ARGV) != 2) {
  printf STDERR "Usage: fgrep.pl smallfile bigfile\n";
  exit(2);
}

my ($small_file, $big_file) = ($ARGV[0], $ARGV[1]);
my ($small_fp, $big_fp, %small_hash, $field);

open($small_fp, "<", $small_file) || die "Can't open $small_file: " . $!;
open($big_fp, "<", $big_file)     || die "Can't open $big_file: "   . $!;

# store contents of small file in a hash
while (<$small_fp>) {
  chomp;
  $small_hash{$_} = undef;
}
close($small_fp);

# loop through big file and find matches
while (<$big_fp>) {
  # no need for chomp
  $field = (split(/\|/, $_))[1];
  if (defined($field) && exists($small_hash{$field})) {
    printf("%s", $_);
  }
}

close($big_fp);
exit(0);

我使用file1.txt中的14K行和file2.txt中的130M行运行了上述脚本。它在大约13秒内完成了126K场比赛。这是time相同的输出:

real    0m11.694s
user    0m11.507s
sys 0m0.174s

我运行了@Inian的awk代码:

awk 'FNR==NR{hash[$1]; next}{for (i in hash) if (match($0,i)) {print; break}}' file1.txt FS='|' file2.txt

它比Perl解决方案慢得多,因为它使file2.txt中的每一行循环14K次-
这确实很昂贵。它在处理了592K条记录file2.txt并产生了40K条匹配的线后中止。这是花了多长时间:

awk: illegal primary in regular expression 24/Nov/2016||592989 at 592989
 input record number 675280, file file2.txt
 source line number 1

real    55m5.539s
user    54m53.080s
sys 0m5.095s

使用@Inian的其他awk解决方案可以消除循环问题:

time awk -F '|' 'FNR==NR{hash[$1]; next}$2 in hash' file1.txt FS='|' file2.txt > awk1.out

real    0m39.966s
user    0m37.916s
sys 0m0.743s

time LC_ALL=C awk -F '|' 'FNR==NR{hash[$1]; next}$2 in hash' file1.txt FS='|' file2.txt > awk.out

real    0m41.057s
user    0m38.475s
sys 0m0.904s

awk 鉴于我们不必编写整个程序来做到这一点,因此在这里给人留下了深刻的印象。

我也运行了@oliv的Python代码。完成这项工作大约花了15个小时,看起来效果不错。构建大型正则表达式的效率不及使用哈希查找的效率。这里的time输出:

real    895m14.862s
user    806m59.219s
sys 1m12.147s

我试图按照建议使用parallel。但是,fgrep: memory exhausted即使块大小很小,它也会因错误而失败。

令我惊讶的是,这fgrep完全不适合这样做。22小时后我终止了它,并产生了约10万次匹配。 我希望fgrep有一个选项可以强制将其内容-f file保留在哈希中,就像Perl代码所做的那样。

我没有检查join方法-我不需要排序文件的额外开销。而且,由于fgrep性能不佳,我认为join这样做不会比Perl代码更好。

感谢大家的关注和回应。



 类似资料:
  • 问题内容: 我正在使用以下外壳程序脚本将一个文件的内容查找到另一个文件中: 我正在执行脚本,但未显示CSV文件中的内容。我的contents.txt文件还包含CSV文件中的数字,例如或。我的工作有什么问题吗? 问题答案: 本身能够做到。只需使用标志: 是每行包含一个模式的文件;并且是要在其中进行搜索的东西文件。 请注意,即使每行的内容看起来像一个正则表达式,也要强制将每行视为一个模式,您应该使用f

  • 问题内容: 我正在Linux系统上使用非常大的文本文件(〜11GB)。我正在通过正在检查文件错误的程序来运行它。一旦发现错误,我需要修复该行或完全删除该行。然后重复… 最终,一旦我对流程感到满意,我便将其完全自动化。但是,现在让我们假设我正在手动运行它。 从此大文件中删除特定行最快(就执行时间而言)是什么?我想到了用Python进行此操作…但是可以接受其他示例。该行可能在文件中的 任何位置 。 如

  • 本文向大家介绍PowerShell查找分区中最大文件的方法(查找文件并按大小排序),包括了PowerShell查找分区中最大文件的方法(查找文件并按大小排序)的使用技巧和注意事项,需要的朋友参考一下 本文介绍一个PowerShell命令,用于将某个目录或磁盘(如D盘)下占用空间最大的前几个文件。这个任务在其它编程语言中,可能要大段大段的代码,而在PowerShell中,我们只需要一行。 当我们发现

  • 问题内容: 在一个文本文件中,我有150个字。我还有另一个文本文件,大约有100,000行。 如何检查属于第一个文件的每个单词是否在第二个文件中? 我曾考虑过使用,但找不到如何使用它来阅读原始文本中的每个单词。 有没有办法做到这一点?还是其他解决方案? 我尝试使用此shell脚本,但它几乎匹配每一行: 我发现的另一种方法是: 问题答案: 您可以使用: 否则匹配完整的单词: 更新: 根据评论:

  • 问题内容: 我有多个3 GB的制表符分隔文件。每个文件中有2000万行。所有行都必须独立处理,任何两行之间都没有关系。我的问题是,什么会更快A.使用以下命令逐行阅读: 还是B.将文件分块读取到内存中并进行处理,例如一次250 MB? 处理不是很复杂,我只是在column1到column2的值中抓取值,等等。可能需要将一些列值加在一起。 我在具有30GB内存的Linux机器上使用python 2.7

  • 问题内容: 已锁定 。该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 我试图找到一个目录中存在的文件,而不是另一个目录中的文件,我尝试使用以下命令: 与上面的命令,它会找到这两个文件的问题,但不是还有文件而不是在, 我试图在文件中找到文件,但不仅在其中。 这是我的数据的一小部分样本 在我脑海里的另一个问题是,我怎么能找到的文件,而不是在或在一个单一的命令?