在大文件中搜索一个大列表

42

我目前正在尝试使用grep命令在一个非常大的id列表(约5000个)中对比一个更大的csv文件(300万行)。

我想要找到所有包含来自id文件的id的csv行。

我的天真做法是:

cat the_ids.txt | while read line
do
  cat huge.csv | grep $line >> output_file
done

但这需要太长时间了!

是否有更高效的方法来解决这个问题?


要在文件中查找所有字符串,您可以在FOR循环中运行grep:https://unix.stackexchange.com/a/462445/43233 - Noam Manos
4个回答

52
尝试
grep -f the_ids.txt huge.csv

此外,由于您的模式似乎是固定字符串,提供-F选项可能会加快grep的速度。

   -F, --fixed-strings
          Interpret PATTERN as a  list  of  fixed  strings,  separated  by
          newlines,  any  of  which is to be matched.  (-F is specified by
          POSIX.)

25

可以使用grep -f来实现:

grep -f the_ids.txt huge.csv > output_file

根据 man grep:

-f FILE, --file=FILE

从文件中获取模式,每行一个。空文件不包含任何模式,因此不匹配任何内容。(-f 由 POSIX 规范定义。)

如果您提供一些示例输入,则我们甚至可以更进一步改善 grep 条件。

测试

$ cat ids
11
23
55
$ cat huge.csv 
hello this is 11 but
nothing else here
and here 23
bye

$ grep -f ids huge.csv 
hello this is 11 but
and here 23

13

grep -f filter.txt data.txtfilter.txt超过几千行时变得难以管理,因此不是这种情况下的最佳选择。 即使使用grep -f,我们仍需要记住以下几点:

  • 如果需要在第二个文件中匹配整行,请使用-x选项
  • 如果第一个文件具有字符串而不是模式,请使用-F
  • 如果不使用-x选项,则使用-w防止部分匹配

这篇文章对这个主题进行了很好的讨论(在大型文件上使用grep -f):

这篇文章谈到了grep -vf


总之,处理大文件上的grep -f的最佳方法是:
匹配整行:
awk 'FNR==NR {hash[$0]; next} $0 in hash' filter.txt data.txt > matching.txt

在第二个文件中匹配特定字段(以“,”分隔符和该示例中的第2个字段为例):

awk -F, 'FNR==NR {hash[$1]; next} $2 in hash' filter.txt data.txt > matching.txt

对于grep -vf

匹配整行:

awk 'FNR==NR {hash[$0]; next} !($0 in hash)' filter.txt data.txt > not_matching.txt

在第二个文件中匹配特定字段(以“,”分隔符和本例中的第2个字段为例):

awk -F, 'FNR==NR {hash[$0]; next} !($2 in hash)' filter.txt data.txt > not_matching.txt

0

如果你使用ugrep来匹配the_ids.txt中的字符串和你的大型huge.csv文件,你可能会获得显著的搜索加速:

ugrep -F -f the_ids.txt huge.csv

这对 GNU grep 也有效,但我期望 ugrep 运行速度能快几倍。


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