grep:仅对每行中的第一个匹配项进行着色

grep:仅对每行中的第一个匹配项进行着色
INPUT | grep --color=always "$string\{1,1\}"

...唉,$string 的每个实例都被突出显示。当我阅读文档时,“{1,1}”应确保仅突出显示第一个实例。或者有更好的工具吗?我无法使用 sed

INPUT | sed -r "s|$string|${red}$string${nrm}|I"

( ${red} 和 ${nrm} 只是颜色代码)

因为这里的 INPUT 是一个可能不区分大小写地找到的文件列表,如果我在 sed 中使用“I”选项,它会强制文件列表的大小写更改为命令输入的确切文本 - 即是的,我想搜索不区分大小写的文件,但无论文件列表中的字符串的大小写如何,都会不敏感地突出显示。

my_command *file_name*

...将使用“查找”来不区分大小写地查找文件,但在列表中我想强调:

file_name 
FILE_nAME 
file_NAME_this_file_has_a_long_file_name

...但仅限第一个实例(文件名可能包含输入字符串的重复项)。因此,在上面的最后一行中,“file_NAME”被突出显示,但“file_name”则没有突出显示。

grep 对于大小写问题没有问题,但 sed 有。 OTOH,sed 知道如何在一场比赛后停止,而 grep 似乎不知道。或者,还有更好的方法?

答案1

如果您grep支持-P类似 perl 的正则表达式,您可以这样做:

grep --color=always -P "^.*?\K\Q$string\E"

每行只能匹配一次,因为我们使用^将匹配锚定在行的开头。接下来是.*?匹配任意数量的字符尽可能少,并且$string\Q/内,因此即使变量碰巧包含正则表达式运算符(除了),\E它的内容也会按字面匹配。指定只有后面的内容才是ept,所以这里是彩色的。$string\E\KK

或者你可以使用真实的东西而不必依赖任何 GNUism:

STRING=$string perl -ne 'print if s/\Q$ENV{STRING}\E/\e[31m$&\e[m/'

即使$string包含也有效\E

答案2

我觉得你如果使用模式替换,则使用sed(匹配不区分大小写,但替换使用捕获的模式,而不是搜索到的模式):

INPUT | sed -r "s|(${string})|${red}\\1${nrm}|I"

另外,正如@don_crissti 注意到的,如果你想给全部的找到模式,您甚至不需要使用捕获组,您可以使用“无论它是什么”&代码,这可能也稍微快一些:

INPUT | sed -r "s|${string}|${red}&${nrm}|I"

使用两个字符串而不是颜色代码似乎可以在我的 bash 上工作:

$ red="_RED_"
$ nrm="_NORM_"
$ string="amd"
$ echo -e "linux-5.4.0-amd-backfire.tar.bz2\\nThis is AMD Radeon\\nNames: Amdiranifani amd Jefri" \
  | sed -r "s|(${string})|${red}\\1${nrm}|I"

linux-5.4.0-_RED_amd_NORM_-backfire.tar.bz2
This is _RED_AMD_NORM_ Radeon
Names: _RED_Amd_NORM_iranifani amd Jefri

第三行中的第二个“amd”不会被替换,所有其他替换都保留其原始大小写。

语法grep意味着它将匹配第一个不断重复模式的一部分,因此在“bababa”中将仅匹配第一个“ba”,但在“baba___ba”中它将匹配第一个和第三个出现的情况。

显然grep 为所有的匹配,因此不能在本例中使用。

相关内容