使用ack或awk或者比grep更好的方式从另一个文件中获取模式?

时间:2012-03-30 04:18:08

标签: regex perl awk grep ack

有没有办法在ack中使用-f作为grep选项从另一个文件中获取一个文件(模式列表)中的模式?我看到-f中有一个ack选项,但与-f中的grep不同。

也许一个例子会给你一个更好的主意。假设我有file1:

file1:
a
c
e

和file2:

file2:
a  1
b  2
c  3
d  4
e  5

我想从file2获取file1中的所有模式,并给出:

a  1
c  3
e  5

可以ack这样做吗?否则,是否有更好的方法来处理作业(例如awk或使用哈希),因为我在两个文件中都有数百万条记录,并且真的需要一种有效的方法来完成?谢谢!

5 个答案:

答案 0 :(得分:8)

这是一个Perl单行程序,它使用散列来保存来自file1的有用键集合,用于在file2的每行迭代中进行O(1)(分摊时间)查找。因此它将在O(m + n)时间内运行,其中m是键集中的行数,n是您正在测试的文件中的行数。

perl -ne'BEGIN{open K,shift@ARGV;chomp(@a=<K>);@hash{@a}=()}m/^(\p{alpha}+)\s/&&exists$hash{$1}&&print' tkeys file2

密钥集将保存在内存中,而file2则逐行对照密钥进行测试。

使用Perl的-a命令行选项,这是同样的事情:

perl -ane'BEGIN{open G,shift@ARGV;chomp(@a=<G>);@h{@a}=();}exists$h{$F[0]}&&print' tkeys file2

第二个版本可能在眼睛上更容易一些。 ;)

你必须要记住的一件事是,你更有可能是IO绑定而不是处理器绑定。因此,目标应该是尽量减少IO的使用。当整个查找键集保存在提供O(1)分摊查找的散列中时。此解决方案可能优于其他解决方案的优点是,某些(较慢)解决方案必须为每行file2一次运行密钥文件(file1)。那种解决方案将是O(m * n),其中m是密钥文件的大小,n是file2的大小。另一方面,该散列方法提供O(m + n)时间。这是一个巨大的差异。通过消除按键的线性搜索,以及通过IO只读一次密钥,可以获得更多好处。

答案 1 :(得分:6)

好吧,如果我们已经从评论切换到答案......; - )

这是一个awk单线程,与DavidO的perl单行程相同,但是在awk中。 Awk比Perl更小,可能更精简。但是有一些不同的awk实现。我不知道你的表现会比其他人更好,还是比perl更好。你需要进行基准测试。

awk 'NR==FNR{a[$0]=1;next} {n=0;for(i in a){if($0~i){n=1}}} n' file1 file2

这应该做什么?

awk脚本的第一部分仅匹配file1中的行(其中当前文件中的记录号等于记录总数),并填充数组。第二部分(在后续文件上运行)逐步遍历数组中的每个项目,并查看它是否可以用作匹配当前输入行的正则表达式。

第二个代码块以“n”开头,在前一个块中设置为0或1。在awk中,“1”的计算结果为true,并且缺少的花括号块被认为等同于{print},因此如果前一个块找到匹配项,则该块将打印当前行。

如果file1包含字符串而不是正则表达式,那么您可以通过将第一次比较替换为if(index($0,i))...来更改此选项以使其更快地运行。

谨慎使用。你的旅费可能会改变。在可能含有坚果的设施中创建。

答案 2 :(得分:1)

nawk 'FNR==NR{a[$0];next}($1 in a)' file3 file4

测试:

pearl.384> cat file3
a
c
e
pearl.385> cat file4
a  1 
b  2 
c  3 
d  4 
e  5
pearl.386> nawk 'FNR==NR{a[$0];next}($1 in a)' file3 file4
a  1 
c  3 
e  5
pearl.387>

答案 3 :(得分:1)

TXR可能是处理您的要求的另一种选择。我太新了,不能写出你需要的内容,但作者经常是StackOverflow的贡献者。虽然我确信你可以用TXR做你需要的,但我不确定它会表现得更好。你需要测试。

值得一看,如果您对用于模式匹配的整个语言感兴趣。 :)

答案 4 :(得分:1)

您可以使用tr将文件转换为ack的正则表达式。我使用sed来删除尾随管道字符。

  

ack“`tr'\ n''|' &lt; patts | sed's /.$//'``

请注意,您需要几个流程,因此awk解决方案可能更有效,但这很容易记住。