【问题标题】:Fast grep / grep for line number only?仅用于行号的快速 grep / grep?
【发布时间】:2012-09-16 23:34:48
【问题描述】:

我正在寻找有关 grep 或类似 grep 工具的帮助。这包括但不限于 grep、egrep、awk、sed 或任何其他用于搜索匹配项的工具。但对于剩下的问题,我只会称它为 grep。

我正在寻找 grep 匹配文件的快速方法,我也在寻找 grep 匹配文件的最快方法,并且只返回行号而不是匹配行的其余部分.我不介意语法是否复杂,只要它快,我将在程序中使用它,复杂性不是问题。

如果我需要对模式进行正则表达式,我也需要这种方法才能工作,这样我也可以搜索范围。因此,如果我需要搜索所有小于 10 的数字(如果命令默认支持它)或者如果它需要一些正则表达式,我只是在寻找我能找到的最快的方法。

谢谢。

编辑

我使用的文件会很大,我的测试文件是 1.9gb

【问题讨论】:

    标签: linux search grep


    【解决方案1】:

    我认为 KingsIndian 使用 grep 的 -m 选项可以达到目标,但如果您的主要目标是速度,则对于这种特殊用途,cut 可能比 awk 快。试试:

    grep -n -m 1 regex file | cut -d: -f1
    

    -d: 参数告诉 cut 使用冒号作为字段分隔符,而 -f1 参数告诉它只输出第一个字段。

    【讨论】:

    • 这和其他的一样工作,但运行速度稍微快了一点,平均几百毫秒。我猜如果我需要跳过一些我会做 grep -n -m 10 regex file |尾-5 |剪切 -d: -f1
    • 在使用cut时,如何指定制表符作为分隔符?
    • cut 默认使用制表符作为分隔符,所以只需去掉 -d:
    【解决方案2】:

    在第一场比赛后停止:

    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 并退出。这是我在这个项目中需要的东西,但也只是暂时输出所有内容。
    • 这真的很酷,我从来没有这样想过。您是否知道在我们要求它执行的操作时是否有比 awk 更快的方法,或者仅返回 grep 是否比强制 awk 循环遍历结果集更快。
    • @WojonsTech grep 在匹配方面比大多数工具都非常有效,而且它仅限于第一个 m 匹配。只有来自 grep 的有限匹配集被传递给 awk。所以应该更快。
    【解决方案3】:

    我不确定这是否很快,但这似乎有效:

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

    【讨论】:

    • 这行得通,但我知道你可以使用 grep -n 来代替使用 nl 来获取带有行号的输出。
    【解决方案4】:

    您可以使用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 &lt;= 10) 更改为 if ($i &gt;= 11 &amp;&amp; $i &lt;= 20) 即可显示结果 11 到 20(含)。

    【讨论】:

    • 不完全是我想要的,但似乎是使用 awk 解决它的编程方式
    • @WojonsTech:请用确切更新您的问题。据我了解,您想搜索一些正则表达式并打印出行号和/或匹配的行。也许我不清楚后者。在这种情况下尝试:awk '/regex/ { print NR, $0 }' file.txt。 HTH。
    • 我也在寻找最少的系统使用方式。我见过人们使用 grep 和 cut 的东西,它的运行速度非常快,不知道 awk 是如何叠加的,但我确实看到它有效,但正在寻找限制结果的最佳方法?
    • @WojonsTech:“正在寻找限制结果的最佳方式”是什么意思?
    • 当您使用 mysql 时,您可以在 LIMIT 子句中进行跳过和限制。因为我想要前 10 个结果之后的 10 个结果。所以显示结果 11-20
    【解决方案5】:

    我刚刚使用非分叉 sed 调用进行了一些测试,但并不走运,但这里参考了 1 GB 文本文件的数字,其中我的 $PATTERN 是最后一行的一部分:

    (剧透:grep 在此操作上快 5 倍以上,awk 最慢)

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2014-07-30
      相关资源
      最近更新 更多