颜色表达式

颜色表达式

我试图让每个 grep 命令以不同的颜色突出显示其结果。我可以用这样的行手动完成:

ls -l GREP_COLORS='mt=01;32' grep c | GREP_COLORS='mt=01;31' grep o | GREP_COLORS='mt=01;34' grep n | GREP_COLORS='mt=01;36' grep f

每个c字符将以绿色突出显示,每个o字符将以红色突出显示,等等......

为了使这个示例正常工作,您需要确保始终使用 --color=alwaysgrep 命令。我已经在我的中设置了这个.bashrc ,所以 grep 总是有颜色:

export GREP_OPTIONS='--color=always'


我试图完成的是用别名包装这个功能,这样我就可以每次调用grep并获得不同的值。GREP_COLORS我理解每个新的管道 grep 需要考虑多个 shell,我试图通过创建一些文件(每种颜色一个)来解决这个问题,以表明它们已经被使用过。

我做了一些尝试,但奇怪的是,这个似乎效果“最好”。我的.bashrc

alias mg="mygrep"
mygrep(){
    # define possible colors
    COLORS=("01;32" "01;31" "01;34" "01;36")
    COUNTER=0
    NUM=0
    # as long as the color has already been used, keep searching
    while [ -f /home/lior/Desktop/mygrep_$NUM ]; do
        # get a random index
        let NUM=`shuf --input-range=0-$(( ${#COLORS[*]} - 1 )) | head -1`
        wait ${!}
        $(( COUNTER+=1 ))
        if [ "$COUNTER" -ge ${#COLORS[@]} ]; then
            # remove all color locks
            rm /home/lior/Desktop/mygrep_*
            wait ${!}
        fi
    done
    # mark this color as used
    touch /home/lior/Desktop/mygrep_$NUM
    wait ${!}

    # lets go!
    GREP_COLORS="mt=${COLORS[$NUM]}" grep "$@"
}

我像这样使用这个别名:

ll | mg c | mg o | mg n | mg f

结果非常酷。然而,有些错误每次都略有不同。以下是一些屏幕截图:

看起来,当 shell 执行每个管道命令时,前一个函数尚未完成其执行。它尝试删除不再存在的文件。我不确定其他command not found错误从何而来。

正如您所看到的,我已经输入了一些wait命令来尝试完成文件操作,但这似乎效果不太好。我已经尝试过的另一件事是使用共享内存,/dev/shm但它产生了类似的结果。

我该如何得到我想要的结果?

笔记:

我正在寻找简单地包装 grep 命令的答案,因为它有很多我想要使用的功能,并且打算在管道之间插入其他逻辑,所以我不想立即提供所有搜索项。我也不是在寻找其他“类似 grep”的工具。抱歉@特登谁已经发布了一个很棒的 Perl 建议。

答案1

这是一种不同的方法。我有一个 Perl 脚本已经发布了在另一个答案中,将以不同颜色突出显示用户提供的图案。该脚本的稍微修改版本将如下所示grep

#!/usr/bin/env perl
use Getopt::Std;
use strict;
use Term::ANSIColor; 

my %opts;
getopts('hic:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

EoF
      exit(0);
    }

my $case_sensitive=$opts{i}||undef;
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
       'bold magenta', 'bold cyan', 'yellow on_blue', 
       'bright_white on_yellow', 'bright_yellow on_red', 'white on_black');
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    $patterns[0]='\*';
}

# Setting $| to non-zero forces a flush right away and after 
# every write or print on the currently selected output channel. 
$|=1;

while (my $line=<>) 
{ 
    my $want=0;
    for (my $c=0; $c<=$#patterns; $c++){
    if($case_sensitive){
        if($line=~/$patterns[$c]/){
           $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ge;
           $want++;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
          $want++;
        }
      }
    }
print STDOUT $line if $want>0;
}

如果将该脚本保存cgrep在您的某个位置PATH并使其可执行,您可以指定最多 10 种不同的模式,每种模式都将以不同的颜色打印:

在此输入图像描述

$ cgrep -h
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

答案2

管道中的每次调用都grep在单独的 shell 中运行,因此您需要在它们之间传递一些状态。以下解决方案是处理该问题的一种粗略方法,使用保留颜色索引的文件和锁定文件来确保同时调用不会读取相同的值:

#!/usr/bin/env bash
color_index_file=~/.gitcolor
color_index_lock_file=/tmp/$(basename $0)

colors=()
for index in {31..34}
do
    colors+=("01;$index")
done

until mkdir "$color_index_lock_file" 2>/dev/null
do
    :
done

color_index=$(($(cat "$color_index_file" || echo 0) + 1))

if [[ $color_index -ge ${#colors[@]} ]]
then
    color_index=0
fi

printf "$color_index" > "$color_index_file"
rmdir "$color_index_lock_file"

GREP_COLORS="mt=01;${colors[$color_index]}" grep --color=always "$@"

测试假设您已命名您的副本cgrep并将其放在您的PATH

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz

答案3

如果您擅长正则表达式,您可能需要查看 grc 和 grcat。 grc 调用 grcat。

grcat 使用配置文件,您可以在其中添加正则表达式来匹配要以每种颜色显示的文本。它还具有许多其他选项。它默认对系统日志文件进行着色。

根据您对最终脚本的想法,您也许只需一个命令即可对输出进行着色。

诀窍是为数据源中的每个“字段”正确指定正则表达式。如果您的数据结构相对统一,这会容易得多。

上次我尝试时,我并没有走得太远,但我可能会再尝试一次,因为我在正则表达式方面比当时更好了一些。

还有 tput 命令可用于直接向终端设备发送信息(如颜色变化)。

下面的帖子介绍了这两种方法。它讨论了 find 命令,但它可以应用于任何命令的输出。

彩色 FIND 输出?

答案4

我经常需要这个,并且我尝试了几种解决方案,包括在 bash 中实现的脚本,例如高亮笔。但是,当使用多个模式、重叠匹配或其他极端情况(如单身的特点火柴

所以我决定推出自己的着色器:

颜色表达式

  • 它有一个定义的着色逻辑:最后一个匹配决定颜色
  • 如果使用捕获组,则只有组内容才会被着色

注意:与 grep 相比,它打印所有输入行,而不仅仅是匹配的行。因此,如果您需要过滤,请使用 grep,然后通过管道输入 colorexp。

例子

基本用法

  • 使用-h/-H选项仅对文本或仅背景进行着色

基本用法示例

重叠比赛 - 最后一场比赛获胜

  • 所有匹配项均已着色,并且将使用最后一个匹配项的颜色

重叠匹配示例

捕获组

  • 当使用捕获组时,只有匹配的组内容才会被着色

图案中各组的颜色不同

  • 当仅给出一种模式时,默认情况下为每个捕获组使用不同的颜色
    • 如果有多个图案,该-G选项可用于强制每个组改变颜色

改变组颜色示例

对图案的所有组使用相同的颜色

  • 当给出多个模式时,默认情况下对模式的所有捕获组使用相同的颜色
    • 如果是单一图案,该-g选项可用于强制使用单一颜色

同一组颜色示例

相关内容