【问题标题】:color the search result when the input is paragraph not a single line当输入是段落而不是单行时,为搜索结果着色
【发布时间】:2017-03-07 18:18:10
【问题描述】:

我正在尝试使用突出显示的搜索字符串打印整个文件的内容。

对于 Record 等于单行的简单文件,我可以使用以下方法轻松完成此操作:

grep --color=auto "myseacrchpattern" inputfile

这里我的记录是段落而不是单行。示例:

CREATE TABLE mytable ( id SERIAL,
name varchar(20),
cost int );

CREATE TABLE notmytable ( id SERIAL,
name varchar(20),
cost int );

如果我确实使用 grep 作为关键字:“notmytable”,它会给我彩色输出,但只打印该行。

grep --color=auto 'notmytable' inputfile
CREATE TABLE notmytable ( id SERIAL,  # <-- "notmytable" is in red but its not the whole query

我需要这样的东西:

CREATE TABLE notmytable ( id SERIAL,   # <---"notmytable" is in red
name varchar(20),
cost int ); 

我可以用 awk 或 perl 打印所需的段落,但如何着色:

awk -v RS=';' -v ORS=';\n' '/notmytable/' inputfile


CREATE TABLE notmytable ( id SERIAL,
name varchar(20),
cost int );

或 perl :

perl -00lne 'print $_ if /notmytable/' inputfile
CREATE TABLE notmytable ( id SERIAL,
name varchar(20),
cost int );

【问题讨论】:

  • 对于 Perl,请参阅 Term::ANSIColor
  • perl -e 'use Term::ANSIColor; print color("red"), "Stop!\n", color("reset"); print color("green"), "Go!\n", color("reset");'
  • 在这种特殊情况下,您可以使用 grep 的上下文控制选项:grep -A 2 notmytable input
  • @Leon,我想到了但无法使用,因为行数在实际数据集中是动态的。
  • @PS。您可以使用此模块动态构建打印语句。

标签: bash perl awk grep


【解决方案1】:
perl "-MTerm::ANSIColor qw(:constants)" -00lnE'
    next if not /notmytable/; 
    for (split "\n") { /notmytable/ ? say RED $_, RESET : say }
' input

:constants 标签提供RED 等。还有其他方法,见Term::ANSIColor

请注意,必须进行一些重复搜索,因为我们需要首先识别段落,然后在正常打印其他行时只打印彩色行。


如果只需要对图案着色,则不需要双重解析(而且更容易更好)

perl -MTerm::ANSIColor -00lnE'say if s/(notmytable)/colored($1,"red")/eg' input

【讨论】:

  • 谢谢,但这会影响整个段落。只需为匹配的字符串着色。我的perl 版本This is perl, v5.10.1
  • @PS。对,看起来是这样,但你的 perl 例子让我不这么认为。这对于单行来说太多了——必须将字符串(段落)分成几行,匹配着色和打印其他...
  • @PS。好的,修复它...随意放入脚本:)
  • @PS。我意识到您实际上可能只想要有颜色的图案,而不是整条线。这更容易,添加到答案中
【解决方案2】:

如果找到匹配所需正则表达式的字符串,则用适当的字符将其包围以更改其颜色并打印包含它的记录:

$ awk -v RS=';' -v ORS=';\n' 'gsub(/notmytable/,"<RED>&</RED>")' file
CREATE TABLE <RED>notmytable</RED> ( id SERIAL,
name varchar(20),
cost int );

只需将 &lt;RED&gt;&lt;/RED&gt; 更改为该颜色的转义序列,例如

awk -v RS=';' -v ORS=';\n' 'gsub(/notmytable/,"\033[31m&\033[0m")' file

或者,如果您不想硬编码这些颜色值,您可以这样做:

awk -v RS=';' -v ORS=';\n' -v red="$(tput setaf 1)" -v nrm="$(tput sgr0)" 'gsub(/notmytable/,red"&"nrm)' file

顺便说一句,如果您在所有记录之间有空行,您可能会发现使用 -v RS= -v ORS='\n\n'-v RS=';' -v ORS=';\n' 更适合您。

【讨论】:

  • 优秀的答案,稍作调整以使其适用于真实数据。虽然有一个问题,为什么gsub不在{...}里面??难道我们不必在{....} 中执行操作吗?
  • 不,您不必在 {} 中添加操作,但请注意,如果您不这样做,则结果将被视为条件,因此可能会导致新操作发生,print $0 默认情况下,如果它的结果​​是true。在这种情况下, gsub() 返回它执行的替换次数的计数,因此我使用它来执行替​​换并在它进行任何替换时触发默认的print $0 操作。相当于写{ if (/foo/) { gsub(/foo/,bar); print $0 } }
【解决方案3】:

将您的awkperl 解决方案与grep 结合起来:

perl -00lne 'print $_ if /notmytable/' input|grep -C1000 notmytable

-C1000 选项使 grep 在匹配行周围保留 1000 行周围的上下文,实际上将 grep 变成了纯粹的着色器而不是行选择器。

你可以把它包装成一个 bash 函数:

function paragrep() { perl -00lne 'print $_ if /'"$1"/ "$2"|grep -C1000 "$1"; }

使用示例:

$ paragrep notmytable input
CREATE TABLE notmytable ( id SERIAL,    # <---"notmytable" is in red
name varchar(20),
cost int );

$

【讨论】:

  • 或者你可以在 perl |grep --color '.*' 之后使用 perl 打印的任何内容都是彩色的。
猜你喜欢
  • 2017-01-30
  • 1970-01-01
  • 2014-05-22
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
相关资源
最近更新 更多