it-swarm.cn

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

说我有以下文件:

$ 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

Screenshot of the two commands

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

127
Michael Mrozek
grep --color -E "test|$" yourfile

我们在这里所做的是与$模式和测试模式相匹配,很显然$没有什么要着色的,因此只有测试模式才可以变色。 -E只是打开扩展的正则表达式匹配。

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

highlight () { grep --color -E "$1|$" "${@:1}" ; }
194
jacksonh
ack --passthru --color string file

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

ack-grep --passthru --color string file
40

使用grep进行适当可移植的另一种方法(除了使用两个正则表达式交替使用,如接受的答案一样)是通过null模式(分别空字符串)。
对于-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
13
don_crissti

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

_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
_

您可以通过更改_1_和_31_和_43_和_\e[_将颜色更改为您喜欢的任何颜色(grep可能很难做到) __)为不同的值。 codes 要使用 all 而不是 place ,但这是一个简短的介绍:1加粗文本,_31_使红色,而_43_则显示黄色背景。 _32_或_33_将具有不同的颜色,而_44_或_45_将具有不同的背景:您明白了。如果您愿意,甚至可以眨眼(用_5_)。

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

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

由于我认为我从来没有在Unix机器上工作过没有已安装Perl(例外嵌入式系统,Linksys路由器等),我想说这是一个通用的解决方案。

11
iconoclast

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

less file

像这样搜索:/pattern Enter

这将:

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

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

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

切换突出显示: Esc u

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

3
Steven Penny

你可以试试:

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

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

2
gvkv

到目前为止给出的答案都没有提供便携式解决方案。

这是便携式1个 Shell函数I 已经发布 作为一个封闭的重复问题,不需要Perlackggrepgsedbash之类,但只需要POSIX Shell和POSIX强制实用程序sedprintf

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

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

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颜色转义序列。

2
jlliagre

ripgrep

ripgrep及其--passthru参数:

rg --passthru pattern file.txt

它是 最快的grepping工具 之一,因为它是建立在 Rust的regex引擎 之上的,它使用有限的自动机,SIMD和积极的文字优化来使搜索变得非常快。

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

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

2
kenorb

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

在管道中:

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

在文件上:

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

归功于 Cyrus在这里的答案

1
Erik Nomitch

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" "[email protected]"
}
0
yurenchen

OP要求grep,这就是I RECOMMEND;但经过努力解决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会以“连续行字符”记住您。

0
Dr Beco