有没有办法在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
或使用哈希),因为我在两个文件中都有数百万条记录,并且真的需要一种有效的方法来完成?谢谢!
答案 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解决方案可能更有效,但这很容易记住。