【问题标题】:Grep characters before and after match?匹配前后的Grep字符?
【发布时间】:2011-11-12 01:05:43
【问题描述】:

使用这个:

grep -A1 -B1 "test_pattern" file

将在文件中匹配模式的前后各产生一行。有没有办法不显示行而是显示指定数量的字符?

我文件中的行非常大,所以我对打印整行不感兴趣,而只是在上下文中观察匹配。有关如何执行此操作的任何建议?

【问题讨论】:

标签: bash grep


【解决方案1】:

前 3 个字符,后 4 个字符

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and

【讨论】:

  • 对于少量数据的一个很好的答案,但是当您匹配 >100 个字符时它开始变慢 - 例如在我的巨型xml文件中,我想要前后{1,200},使用起来太慢了。
  • @amit_g 的 awk 版本要快得多。
  • 在 Mac OSX 上不可用,所以这实际上不是一个广泛可用的解决方案。 -E 版本(如下所列)是更好的解决方案。什么是-P?继续阅读... -P, --perl-regexp 将 PATTERN 解释为 Perl 正则表达式(PCRE,见下文)。这是高度实验性的, grep -P 可能会警告未实现的功能。
  • 在 OSX 上通过:brew install homebrew/dupes/grep 安装并以ggrep 运行。
  • 正如@Benubird 所暗示的那样,这在性能方面不可能用于匹配目标所需的具有中等宽度环境的大型文件。
【解决方案2】:
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

这将匹配您的模式前后最多 5 个字符。 -o 开关告诉 grep 只显示匹配并且 -E 使用扩展的正则表达式。确保在你的表达式周围加上引号,否则它可能会被 shell 解释。

【讨论】:

  • 好答案,有趣的是它在 {} 中的长度上限为 2^8-1,因此 {0,255} 有效 {0,256} 给出 grep: invalid repetition count(s)
  • 随着我增加匹配字符的数量(5 -> 25 ->50),这似乎变得相当低效,知道为什么吗?
【解决方案3】:

你可以使用

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file

【讨论】:

  • 即使文件更大也能很好地工作
  • 如何使用它在每行查找多个匹配项?
  • 花括号对中的第一个数字有什么意义?就像 "grep -E -o ".{0,5}test_pattern.{0,5}" test.txt "中的 0?
  • 确实更快,但不如@ekse 的回答准确。
【解决方案4】:

你的意思是,像这样:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

这将在test_pattern 的任一侧打印最多二十个字符。 \{0,20\} 表示法类似于 *,但指定了 0 到 20 次重复而不是 0 次或多次。-o 表示只显示匹配项本身,而不是整行。

【讨论】:

  • 这个命令对我不起作用:grep: Invalid content of \{\}
【解决方案5】:

我永远不会轻易记住这些神秘的命令修饰符,因此我将top answer 转换为我的~/.bashrc 文件中的函数:

cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search pattern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

下面是实际效果:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

有问题的文件是一个连续的 25K 行,使用常规 grep 找不到您要查找的内容。

请注意调用cgrep 的两种不同方法,与grep 方法相似。

有一种创建函数的“niftier”方法,其中“$2”仅在设置时传递,这将节省 4 行代码。不过我手边没有。像${parm2} $parm2 这样的东西。如果我找到它,我会修改函数和这个答案。

【讨论】:

    【解决方案6】:

    使用gawk,可以使用匹配功能:

        x="hey there how are you"
        echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
        ere   are
    

    如果您对perl 没问题,更灵活的解决方案:以下将在模式前打印三个字符,然后是实际模式,然后在模式后打印五个字符。

    echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
    ey there how
    

    这也可以应用于单词而不仅仅是字符。以下将在实际匹配字符串之前打印一个单词。

    echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
    hey
    

    以下将在模式后打印一个单词:

    echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
    how
    

    以下将在模式之前打印一个单词,然后是实际单词,然后是模式之后的一个单词:

    echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
    hey there how
    

    【讨论】:

      【解决方案7】:

      您可以使用正则表达式 grep 查找 + 第二个 grep 突出显示

      echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string
      

      23_string_and

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-07
        • 1970-01-01
        • 2011-09-16
        • 1970-01-01
        • 1970-01-01
        • 2023-04-06
        • 1970-01-01
        相关资源
        最近更新 更多