快速grep / grep仅返回行号?

5
我需要一些关于grep或类似工具的帮助,这包括但不限于grep、egrep、awk、sed或其他用于搜索匹配项的工具。但是我将在本问题的其余部分中仅称之为grep。
我正在寻找快速搜索文件中匹配项的方法,也在寻找最快的方法来搜索文件中的匹配项,并仅返回所在行号而不是匹配行的其余部分。只要语法快速,我不介意它的复杂性,因为我将在程序中使用它,复杂性不是问题。
如果我需要使用正则表达式来搜索模式,我还需要该方法能够工作,以便我可以搜索范围。因此,如果我需要搜索所有小于10的数字,如果命令默认支持它或者需要一些正则表达式,我只是在寻找我可以找到的最快的方法。
谢谢。
编辑
我处理的文件将非常大,我的测试文件为1.9GB。
5个回答

6

我认为KingsIndian提到的-m选项是正确的,但如果速度是你的主要目标,对于这种特定用途,cut可能比awk更快。尝试使用以下命令:

grep -n -m 1 regex file | cut -d: -f1
< p > -d: 参数告诉 cut 使用冒号作为字段分隔符,而 -f1 参数则告诉它仅输出第一个字段。


这个和其他的一样有效,但平均快了几百毫秒。我猜如果我需要跳过几个,我会执行 grep -n -m 10 regex file | tail -5 | cut -d: -f1。 - WojonsTech
使用cut命令时,如何指定制表符作为分隔符? - Bulrush
默认情况下,cut 命令使用制表符作为分隔符,因此只需删除 -d 参数即可。 - nullrevolution

3
停止于第一次匹配:
grep -n -m 1 str file | awk -F: '{print $1}'

您可以将m的参数值更改为其他值,以在匹配到指定次数后停止。其中awk部分仅用于捕获行号。

要在匹配5个后停止:

grep -n -m 5 str file | awk -F: '{print $1}'

编辑:
你可以使用tail命令来实现。例如,要跳过前5个匹配项并打印接下来的7个:grep -n -m 12 str file| tail -7 | awk -F: '{print $1}'


-m 很酷,你知道是否有一种方法可以跳过前几个结果,然后打印接下来的5个结果并退出吗?这是我在这个项目中需要的东西,但现在只是想先输出所有内容。 - WojonsTech
这真的很酷,我从未想过这种方式。你知道有没有比awk更快的东西来完成我们所要求的操作,或者直接返回grep -no比强制awk循环结果集更快? - WojonsTech
1
@WojonsTech grep在匹配方面比大多数工具更有效率,而且它仅限于前m个匹配项。只有来自grep的这些有限匹配集会传递给awk。因此,它应该更快。 - P.P

1

我不确定这是否快速,但似乎可以工作:

nl -b a "<filename>" | grep "<phrase>" | awk '{ print $1 }'

这个可以运行,但我知道你可以使用grep -n来获取带有行号的输出。 - WojonsTech

1

您可以使用GNU awk进行模式匹配,并简单地打印出行号:

awk '/regex/ { print NR }' file.txt

假设值是以空格分隔的,如果行包含小于10的数字,则可以找到行号:
awk '{ for (i=1; i<=NF; i++) if ($i <= 10) print NR }' file.txt

然而,这将打印每个小于10的数字出现的行号。我相信您可能会发现这不太理想。因此,为了删除每个匹配项的多个重复行号,您可以使用一个数组:

awk '{ for (i=1; i<=NF; i++) if ($i <= 10) array[NR]++ } END { for (i in array) print i }' file.txt

如果您需要排序输出,请使用管道符号 sort -n。如果您更喜欢一种更优雅的解决方案(即不使用管道符号):
awk '{ for (i=1; i<=NF; i++) if ($i <= 10) array[NR]++ } END { for (j in array) sorted[k++]=j+0; n = asort(sorted); for (j=1; j<=n; j++) print sorted[j] }' file.txt

编辑:

在上述任何一个awk命令中,只需将if ($i <= 10)更改为if ($i >= 11 && $i <= 20)以显示11到20的结果。


不完全是我所寻找的,但似乎这是使用awk解决问题的编程方式。 - WojonsTech
@WojonsTech:请更新您的问题,确切地说明您想要做什么。从我的理解来看,您想要搜索一些正则表达式并打印出行号和/或匹配行。也许我没有清楚地表达后者。在这种情况下,请尝试:awk '/regex/ { print NR, $0 }' file.txt。希望对您有所帮助。 - Steve
我也在寻找最简捷的使用方法。我看到一些人使用 grep 和 cut,整体效果还不错,但不确定 awk 的效果如何,请问是否有更好的限制结果的方法? - WojonsTech
@WojonsTech:你的意思是“正在寻找限制结果的最佳方法”吗? - Steve
当您使用MySQL时,可以在LIMIT子句中使用skip和limit。因此,我想要在第一个10个结果之后获得10个结果。因此显示11-20的结果。 - WojonsTech

1

我刚刚进行了一些关于非分叉sed调用的测试,并没有成功,但为了参考,这里是一千兆字节文本文件的数字,其中我的$PATTERN是最后一行的一部分:

(提示: 在此操作中grep比sed快5倍以上,awk最慢)

user@box:~$ ls -lh /dev/shm/test 
-rw-r--r-- 1 user user 979M Jul  8 09:50 /dev/shm/test
user@box:~$ sed --version | head -n1
GNU sed-Version 4.2.1
user@box:~$ time sed -n "/$PATTERN/{=;q}" /dev/shm/test
206558
real 0m6.835s user 0m6.160s sys 0m0.648s
user@box:~$ grep -V | head -n1
grep (GNU grep) 2.14
user@box:~$ time grep -n -m 1 "$PATTERN" /dev/shm/test | cut -d: -f1
206558
real 0m1.337s user 0m0.592s sys 0m0.736s
用户@框:〜$ awk --version | head -n1
GNU Awk 4.0.1
用户@框:〜$ time awk "/$PATTERN/ { print NR }" /dev/shm/test
206558
真实 0m7.176s 用户 0m6.356s 系统 0m0.776s

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