使用Grep命令将结果输出到多个文件

4
我可以帮您进行翻译。以下是需要翻译的内容:

我有一个超过6GB的大文件,以及约1000个模式。我想将与每个模式匹配的行提取到单独的文件中。例如,我的模式如下:

1
2

我的文件:

a|1
b|2
c|3
d|123

作为输出,我想要两个文件:

1:

a|1
d|123

2:

b|2
d|123

我可以通过多次使用grep命令来完成,但是对于1000个模式和大文件来说效率很低。我也尝试了类似这样的方法:

grep -f pattern_file huge_file

但它只会生成一个输出文件。我无法对我的大文件进行排序 - 这需要太多时间。也许AWK可以做到?

5个回答

5
awk -F\| 'NR == FNR {
  patt[$0]; next
  }
{
  for (p in patt)
    if ($2 ~ p) print > p
  }' patterns huge_file

使用某些awk实现时,您可能会达到最大打开文件限制。如果是这种情况,请告诉我,以便我可以发布替代解决方案。

P.S.:此版本将一次只保持一个文件处于打开状态:

awk -F\| 'NR == FNR {
  patt[$0]; next
  }
{
  for (p in patt) {
    if ($2 ~ p) print >> p
    close(p)
    }
  }' patterns huge_file

谢谢。我根据您的答案编写了脚本。 - mefju

5
如果我理解问题正确的话,你可以使用bash“进程替换”来完成此操作。例如,考虑以下示例数据:
$ cal -h
   September 2013     
Su Mo Tu We Th Fr Sa  
 1  2  3  4  5  6  7  
 8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
22 23 24 25 26 27 28  
29 30 

接着可以使用 grep 命令将特定的行输出到不同的文件中,只需一条指令即可:

$ cal -h \
    | tee >( egrep '1'    > f1.txt ) \
    | tee >( egrep '2'    > f2.txt ) \
    | tee >( egrep 'Sept' > f3.txt ) 

在这种情况下,每个 grep 都在处理整个数据流(这可能是你想要的,也可能不是:与仅运行并发的 grep 进程相比,这可能不会节省太多时间):
$ more  f?.txt
::::::::::::::
f1.txt
::::::::::::::
   September 2013     
 1  2  3  4  5  6  7  
 8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
::::::::::::::
f2.txt
::::::::::::::
   September 2013     
 1  2  3  4  5  6  7  
 8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
22 23 24 25 26 27 28  
29 30                 
::::::::::::::
f3.txt
::::::::::::::
   September 2013     

如果有1000个模式,它将运行1000个grep进程。对于这种情况是错误的。 - xoid
这只是一个简单的bash语法示例,可能不太熟悉。(“许多进程==不好”绝不是公理——例如,考虑“大数据”处理架构。)但你是对的——对于1000个模式,这根本是不切实际的。(你需要一个脚本来生成脚本……)当工作被分解成片段时,许多进程才有优势——而在这里,它并没有。这是真正的警告/问题。此外……这是一次性的事情(没有时间/空间要求)吗?还是它是业务工作流的一部分?如果是后者,map/reduce + hadoop可能是更好的选择。 - michael

1

这个方法对你可能有效(尽管sed不是最快的工具!):

 sed 's,.*,/&/w &_file,' pattern_file > sed_file

然后对源文件运行此文件:

 sed -nf sed_file huge_file

我进行了一次粗略测试,使用的GNU sed版本4.1.5可以轻松地打开1000个文件,但是您的Unix系统可能会有更小的限制。


0

我有这个需求,所以我在我自己的grep.c副本中添加了这个功能。但是我突然想到:如果主要目标是避免多次对大量输入进行处理,那么你可以在巨大的输入上运行egrep一次以搜索任何一个模式(我知道这不是你想要的),并将其输出重定向到一个中间文件,然后对该中间文件进行多次处理,每个模式处理一次,每次重定向到不同的最终输出文件。


0

Grep 无法将不同模式的匹配项输出到不同的文件中。Tee 可以将其输入重定向到多个目标,但我认为这不是你想要的。

要么使用多个 grep 命令,要么编写一个程序在 Python 或其他你喜欢的语言中完成它。


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