将grep上下文限制为N个字符


31

我必须遍历某些JSON文件,其中行长超过几千个字符。如何限制grep在匹配的左右两侧最多显示N个字符的上下文?只要grep可以在常见的Linux软件包中使用,除grep以外的任何其他工具都可以。

这将是虚拟grep开关Ф的示例输出:

$ grep -r foo *
hello.txt: Once upon a time a big foo came out of the woods.

$ grep -Ф 10 -r foo *
hello.txt: ime a big foo came of t



3
不能重复。这是大约±个字符,但建议的替代方法是大约±个行。(不过,您对stackoverflow的引用很好。)
roaima

Answers:


22

使用GNU grep

N=10; grep -roP ".{0,$N}foo.{0,$N}" .

说明:

  • -o =>仅打印您匹配的内容
  • -P =>使用Perl样式的正则表达式
  • 正则表达式表示将0匹配到$N字符,foo然后将0 匹配到$N字符。

如果您没有GNU grep

find . -type f -exec \
    perl -nle '
        BEGIN{$N=10}
        print if s/^.*?(.{0,$N}foo.{0,$N}).*?$/$ARGV:$1/
    ' {} \;

说明:

由于我们不能再依赖于grepGNU了grep,因此我们利用它find来递归搜索文件(-rGNU 的操作grep)。对于找到的每个文件,我们执行Perl代码段。

Perl开关:

  • -n 逐行读取文件
  • -l 删除每行末尾的换行符,然后在打印时放回
  • -e 将以下字符串视为代码

Perl片段的功能与基本上相同grep。首先,将变量设置$N为所需的上下文字符数。这BEGIN{}意味着在执行开始时仅执行一次,而不对每个文件中的每一行执行一次。

如果正则表达式替换有效,则为每行执行的语句将打印该行。

正则表达式:

  • 匹配任何旧事物懒洋洋地1处行的开始(^.*?),然后.{0,$N}作为grep的情况下,随后foo紧接着又.{0,$N}终于懒洋洋地匹配任何旧事物,直到行结束(.*?$)。
  • 我们用代替$ARGV:$1$ARGV是一个神奇的变量,用于保存正在读取的当前文件的名称。$1括号匹配的是什么:在这种情况下是上下文。
  • 两端都需要延迟匹配,因为贪婪的匹配会先吃掉所有字符,然后foo再匹配(因为.{0,$N}允许匹配零次)。

1 也就是说,最好不要匹配任何东西,除非这会导致整体匹配失败。简而言之,请尽可能少地匹配字符。


很好谢谢。这样做的缺点是不仅突出显示了搜索的文本,而且突出显示了整个输出,但是可以通过| grep foo在末尾附加内容来解决(但是在此过程中失去了文件名的突出显示)。
dotancohen 2014年

1
@dotancohen我想你不可能全部赢得他们:)
约瑟夫·R。

使用GNU,grep您可以根据通过环境变量应用的标志来指定匹配颜色/应用。所以也许您甚至都可以赢得全部胜利(没有保证-甚至不确定在这种情况下是否会奏效),但是我个人没有看到这里的意义...无论如何...继续比赛。
mikeserv

好答案。请注意,zsh在示例中,我无法通过N = 10使它正常工作。但是,如果我export N=10在运行命令之前,它确实可以工作。任何想法如何调整示例以使用zsh?
加布·科普利2015年

或者perl -lne 'print "$ARGV: $_" for /.{0,10}foo.{0,10}/g'
斯特凡Chazelas

19

尝试使用这个:

grep -r -E -o ".{0,10}wantedText.{0,10}" *

-E告诉您要使用扩展的正则表达式

-o告诉您只想打印匹配项

-r grep在文件夹中递归查找结果

正则表达式:

{0,10}告诉您要打印多少个任意字符

表示任意字符(字符本身在这里并不重要,只是其数字)

编辑:哦,我知道,约瑟夫推荐的解决方案与我差不多:D


谢谢。尽管本质上是相同的解决方案,但令人鼓舞的是,这是两个人独立推荐时的最佳方法。
dotancohen 2014年

不客气,Unix社区完全必须合作,这就是我们的
宗旨

2
尽管它们相似,但可接受的答案对我不起作用(仍然排成一排),但确实如此。N = 10的技巧不适用于bash shell。
meesern

cygwin -E中的速度明显快于-P
Bob Stein

2

摘自:http : //www.topbug.ne​​t/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/https:// stackoverflow。 com / a / 39029954/1150462

建议的方法".{0,10}<original pattern>.{0,10}"非常好,除了突出显示的颜色经常被弄乱。我创建了一个具有类似输出的脚本,但是颜色也被保留了:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 | grep --color=none -oE ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

假设脚本另存为grepl,则grepl pattern file_with_long_lines应该显示匹配的行,但匹配字符串的周围只有10个字符。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.