五彩的Grep


30

我正在尝试让每个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考虑多个外壳的问题,并且我试图通过创建一些文件(每种颜色一个)来解决这个问题,以表明它们已被使用。

我做了一些尝试,但奇怪的是,这似乎是“最好的”方法。我在我的.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在执行每个pipe命令时一样,先前的函数尚未完成其执行。它尝试删除不再存在的文件。我不太确定这些其他command not found错误来自何处。

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

我将如何获得想要的结果?

注意:

我正在寻找简单地包装grep命令的答案,因为它具有许多我想使用的功能,并且打算在管道之间插入其他逻辑,因此我不想一次提供所有搜索词。我也没有在寻找其他“类似grep”的工具。对不起@terdon,他已经发布了一个很棒的perl建议。


您的第一个示例与您在其余部分中说明的内容不符,只是说说而已。
伯恩哈德

@bernhard我不明白你的意思。我的意图是使用别名作为使用管道的更大命令的一部分...请让我知道您在说什么矛盾...
Lix 13'9

我以为您也想在管道外使用别名。无论如何,您的第一个示例对我不起作用。你尝试了alias mg="mygrep; grep"吗?
伯恩哈德

@Bernhard-我正在使用Ubuntu 12.04盒子。如果有细微的差异,我也不会感到惊讶...我确实尝试了您的建议,但问题是它mygrep;本身变成了一个新命令,并且数据流丢失了。从传入的管道ls将传递mygrep;给grep而不是grep。至少我是这样理解的。
Lix

@Bernhard-啊..我想我知道为什么它对您不起作用。您需要确保--color=always所有grep命令上都有。我已将其全局设置在.bashrc。我已将其编辑到帖子中。
Lix 2013年

Answers:


6

这是另一种方法。我有一个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;

5

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

#!/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

真正需要维护的唯一变量是COLOR_INDEXGREP_COLORS。我尝试在功能末尾导出这些文件,但没有成功。这是你的意思吗?简单地拥有export VAR吧?
Lix 2013年

哦-是的COLOR_TOGGLE。感谢您抓住它:)
Lix

1
@ l0b0导出对我也不起作用,必须暂时降低投票权,直到它真正回答问题为止。
伯恩哈德

@Bernhard这对您有用吗?
l0b0 2013年

感谢您的输入!我已经采纳了您的grep "$@"建议-整理出别名以运行该函数,然后运行grep。
Lix 2013年

1

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

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

根据最终脚本的构想,您也许可以只用一个命令为输出着色。

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

上次尝试时,我并没有走得太远,但是我可能还会再尝试一次,因为我比以前更擅长正则表达式。

还有一个tput命令,可用于直接将信息(例如颜色更改)发送到终端设备。

两种方法都在下面的文章中介绍。它讨论了find命令,但是它可以应用于任何命令的输出。

有色的FIND输出?

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.