说服grep输出所有行,而不仅仅是匹配的行


121

说我有以下文件:

$ cat test

test line 1
test line 2
line without the search word
another line without it
test line 3 with two test words
test line 4

默认情况下,grep返回包含搜索词的每一行:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

--color参数传递给grep会使其突出显示与搜索表达式匹配的行的一部分,但仍仅返回包含该表达式的行。有没有一种方法可以grep输出源文件中的每一行,但突出显示匹配项?

我目前的骇客技巧(至少在没有10000+连续行且没有匹配项的文件上)是:

$ grep -B 9999 -A 9999 test test

这两个命令的屏幕截图

如果grep不能完成此操作,是否还有另一个提供相同功能的命令行工具?我玩弄了ack,但是似乎也没有选择。


1
可能的跨站点重复项:stackoverflow.com/questions/981601/…两者的最高答案是相同的。
Ciro Santilli新疆改造中心法轮功六四事件

1
您可以使用.I -C 9999代替-A 9999 -B 9999grep -C 9999 pattern file
neo

Answers:


181
grep --color -E "test|$" yourfile

我们在这里所做的是将$图案和测试图案进行匹配,显然$没有什么要着色的,因此只有测试图案才会变色。在-E刚刚开启扩展正则表达式匹配。

您可以像这样轻松地创建一个函数:

highlight () { grep --color -E "$1|$" "${@:1}" ; }

14
真是太厉害了!
gvkv

3
而作为一个功能:highlight () { grep --color -E "$1|$" $2 ; }。用法:highlight test yourfile
Stefan Lasiewski

2
@StefanLasiewski:"$2"也应引用。
丹尼斯·威廉姆森

6
更好的方法是:highlight () { grep --color -E "$1|$" "$@" }允许名称中带有空格的文件以及多个文件。
Mike DeSimone

15
@MikeDeSimone-但这也将包含"$1"在文件中。使用highlight () { grep --color -E "$1|$" "${@:1}" }
克里斯·

39
ack --passthru --color string file

对于Ubuntu和Debian,请使用ack-grep而不是ack

ack-grep --passthru --color string file

1
哦,这在手册页中很明显;我瞎了。谢谢
Michael Mrozek

grap的模式可以用明确指定--regexp string;ack / ack-grep等效项是--match string
Rhubbarb,2015年

ack --passthru用perl 模拟:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon

ack --passthru也适用于流!例如,ifconfig | ack --passthru inet
honkaboy

12

另一种方式来做到这一点正确便携grep(除了使用两个正则表达式与交替作为公认的答案)是通过空模式(分别为空字符串)。根据标准
它应该-E-F交换机和交换机同样工作良好,因为:

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

-F
    Match using fixed strings.
    [...] A null string shall match every line.

所以这只是运行问题

grep -E -e '' -e 'pattern' infile

和分别

grep -F -e '' -e 'string' infile

1
或者只是grep -F -e '' -e 'string'
斯特凡Chazelas

它适用于GNU grep 2.25,busybox grep和传家宝工具。
斯特凡Chazelas

好的,我不好,seq 3 | grep -F -e '' -e 2在2.27(和2.26,但不是2.25,而不是git头)中仅输出2。仅带有-F(不带有-E或不带有)。IOW,只有2.26和2.27似乎有此错误,并且只有-F。
斯特凡Chazelas

请注意,seq 3 | grep -F -e '' -e '' -e 2 似乎与2.27合作以及
斯特凡Chazelas

1
此答案中给出的方法简单,正确,并且看起来非常快正如您所说,它可以自动运行-F,从而无需担心出现在其中的字符string。您可能要提一提--color; 由于此答案在页面上浮动(通过投票查看)时,更多的人可能最终会在其他答案之前阅读它。
伊莱亚·卡根

11

我具有用于此类事情的以下功能:

highlight () {
    perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

从内部看,它看起来很丑陋,非常好用,就像这样:

cat some_file.txt | highlight some_word

或者,对于一个更真实的示例:

tail -f console.log | highlight ERROR

您可以通过将1and 3143(after \e[)更改为不同的值,将颜色更改为任何您喜欢的颜色(grep可能很难做到)。该代码到使用的是所有的地方,但这里有一个快速的介绍:1个加粗文本中,31使得红色,43给人以黄色背景。 3233使用不同的颜色,4445使用不同的背景:您明白了。5如果您愿意,甚至可以使其闪烁(带有)。

它不使用任何特殊的Perl模块,Perl 几乎无处不在,因此我希望它几乎可以在任何地方工作。grep解决方案非常聪明,但是grep上的--color开关并非在所有地方都可用。例如,我刚刚在运行bash,运行ksh的Solaris盒和运行zsh的本地Mac OS X机器上尝试了此解决方案。一切都很好。但是,Solaris使该grep --color解决方案陷入困境。

另外,ack非常棒,我推荐给尚未发现ack的任何人,但是在我使用的许多服务器中的一些服务器上安装它时遇到了一些问题。(我忘记了原因:我认为它与所需的Perl模块有关。)

因为我不认为我曾经没有安装Perl 的Unix机器上工作(嵌入式系统,Linksys路由器等除外),所以我想这是一个通用的解决方案。


3

除了使用Grep,还可以使用Less:

less file

像这样搜索: /pattern Enter

这将:

  1. 滚动到第一条匹配线
  2. 从那里开始输出每一行
  3. 突出显示所有比赛

滚动到下一条匹配的行: n

滚动到上一条匹配的行: N

切换突出显示: Esc u

您也可以根据需要更改突出显示颜色


2

你可以试试:

perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

但是,它不是很便携,即使安装了Perl,也可能需要下载另一个模块。此外,它将为整行着色,而不仅仅是搜索词。


2

ripgrep

ripgrep与它的--passthru参数一起使用:

rg --passthru pattern file.txt

它是最快的grepping工具之一,因为它是基于Rust的正则表达式引擎构建的,该引擎使用有限自动机,SIMD和积极的文字优化来使搜索变得非常快。

--passthru -打印匹配和不匹配的行。

实现类似效果的另一种方法是修改模式以匹配空字符串。例如,如果您使用进行搜索,rg foo则使用rg "^|foo"代替会在搜索到的每个文件中发出每一行,但是仅会出现foo。该标志启用相同的行为,而无需修改模式。


1

对于GNU grep,有一种更简便的方法,但我认为它不是可移植的(即BSD grep):

在管道中:

cat <file> | grep --color=always -z <query>

在文件上:

grep --color=always -z <query> <file>

在此归功于Cyrus的回答


1
这不是您(和Cyrus)所想的答案。它具有将整个文件视为一行的效果。因此,(1)如果该文件是非常大的,有可能是运行内存的可能性,以及(2)如果所述文件不包含所述图案在所有,则什么也不会输出。而且你是对的;它不是普遍可用的。(但话又说回来,--color这也不是标准的。)
G-Man

支持什么版本的grep?在grep 2.5.4上,-z似乎不可用...
Alex

1

到目前为止,给出的答案均未提供可移植的解决方案。

这里是一个便携式1个外壳功能我已经张贴在一个封闭的,不需要提供非标刀具或非标准的扩展名重复的问题perlackggrepgsedbash和喜欢,但只需要一个POSIX外壳和POSIX强制公用事业sedprintf

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "$@"
}

您可以通过以下方式使用它:

grepc string_to_search [file ...]

可以通过使用sed命令参数中的以下代码之一来调整突出显示颜色(此处32m为绿色):

30m black
31m red
33m yellow
34m blue
35m magenta
36m cyan
37m white
7m reverse video

1只要您的终端支持ANSI颜色转义序列。


0

一个sed版本,适用于bashash

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "$@"
}

0

OP要求的grep,这是我的建议 ; 但是,在尝试解决的问题后sed,以下是一个简单的解决方案:

sed $'s/main/\E[31m&\E[0m/g' testt.c

要么

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

会涂main成红色。

  • \E[31m :红色开始顺序
  • \E[0m :成品色标
  • & :匹配的模式
  • /g :一行中的所有单词,而不仅仅是第一个
  • $'string' 是bash字符串,带有转义字符

关于grep,它也可以使用^(行的开头)代替$(行的结尾)。例:

egrep "^|main" testt.c

只是为了显示这个疯狂的别名(我不推荐),您甚至可以使用开放引号:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

全部工作!:)不用担心,如果您忘了关闭引号,bash会以“连续行字符”记住您。

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.