12

I need grep output with context, in color, and blank lines as group separator. In this question, I learned how to define custom group-separator, and I have constructed my grep command like this:

grep --group-separator="" --color=always -A5

but the group separator is actually not empty, instead it still contains the color code (i.e. [[36m[[K[[m[[K). This is because I am using --color=always. But I need color in my grep command, and I need separator to be blank line (for further processing)

How can I combine these two conditions?

Martin Vegter
  • 358
  • 75
  • 236
  • 411
  • If you have --color=always the match will print with color, and if you have the --group-separator="" set to the empty string you will get a blank line after your matching group. Please try again leaving the --group-separator="" with the empty string, not a specific color escape, and then explain what is not working. – bsd Feb 04 '14 at 21:12
  • @bdowning that's what the OP tried. The code he mentions is not visible in the terminal output. Try passing the output through od -c to see the hidden characters that appear in the blank lines. – terdon Feb 04 '14 at 21:20
  • @terdon, I see it with od. – bsd Feb 04 '14 at 22:37

3 Answers3

10

If you use the GREP_COLORS environment variable you can control specific colors for each type of match. man grep explains the use of the variable.

The following command will print a colored match, but nothing on the line that separates the group, just a blank line. Piped through od you'll see the color escape before and after the match, but only \n\n at the group separation.

GREP_COLORS='ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=' grep --group-separator="" --color=always -A5

Unsetting the se component will suppress the printing of color in the group separator.

Since my example above used all of the default values for GREP_COLORS the following will work as well.

GREP_COLORS='se=' grep --group-separator="" --color=always -A5

If you're not using a bashlike shell, you might need to export GREP_COLORS first.

bsd
  • 11,036
5

Personally, I do that using Perl, not grep. I have a little script that will highlight a given pattern in color:

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

my %opts;
getopts('hsc:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
DESCRIPTION

$0 will highlight the given pattern in color. 

USAGE

$0 [OPTIONS] -l PATTERN FILE

If FILE is ommitted, it reads from STDIN.

-c : comma separated list of colors
-h : print this help and exit
-l : comma separated list of search patterns (can be regular expressions)
-s : makes the search case sensitive

EoF
      exit(0);
    }

my $case_sensitive=$opts{s}||undef; 
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
           'bold magenta', 'bold cyan', 'yellow on_magenta', 
           'bright_white on_red', 'bright_yellow on_red', 'white on_black');
## user provided color
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
## read patterns
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    die("Need a pattern to search for (-l)\n");
}

# 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=<>) 
{ 
    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;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
        }
      }
    }
    print STDOUT $line;
}

If you save that in your path as color, you can get your desired output by running

grep --group-separator="" --color=never -A5 foo | color -l foo

That way, the script is coloring the matches for you and you can tell grep not to use colors and avoid this problem.

terdon
  • 242,166
  • Please, @terdon add it to a gist, and link it back here, so it will be easier to follow any evolution. – Rafareino Aug 19 '15 at 22:40
  • @Rafareino yeah, I'm afraid I don't really use such tools. I do actually have a repository but it is very rarely updated. I keep meaning to set one up and use it properly but I never seem to get round to it. – terdon Sep 03 '15 at 12:18
  • So I made a small correction right here, sadly, I needed to include a comment to reach the minimum edit @terdon – Rafareino Sep 04 '15 at 14:17
0

I use rcg (Regexp Colored Glasses) by Rob Flickenger. Here's a copy:

#!/usr/bin/perl -w

=head1 NAME

rcg - Look at the world through Regex Colored Glasses

=head1 SYNOPSIS

rcg sudo: RED &lt; /var/log/messages

tail /var/log/syslog | rcg '\d\d:\d\d:\d\d' &quot;BOLD . BLUE&quot; 

=head1 DESCRIPTION

rcg is a simple filter that uses Term::ANSIColor to colorize arbitrary regexs, specified on the commandline. It is intended to help visually slog through log files.

You must pass 'rcg' an even number of commandline parameters. The odd terms specify the regex, the even terms specify the color.

=head1 EXAMPLES

Suppose you wanted anything with the word 'sendmail' in your messages log to show up magenta, instead of grey:

rcg sendmail MAGENTA &lt; /var/log/messages | less -r

The 'less -r' is optional, but handy if you have less(1) installed.

You can use any arbitrary regex as an odd term:

rcg '\d+\.\d+\.\d+\.\d+' GREEN &lt; /var/log/maillog

Or chain colors together:

tail -50 /var/log/messages | rcg WARNING &quot;BOLD . YELLOW . ON_RED&quot; 

Or specify any number of regex / color code pairs on a single commandline. This is where teeny shell scripts would come in handy (one for messages, one for firewall logs, one for apache...)

See the Term::ANSIColor docs for the full list of colors and combinations.

Some other useful strings:

'\w+=\S+'               variables, like TERM=xyz
'\d+\.\d+\.\d+\.\d+'        probably an IP address
'^(J|F|M|A|S|O|N|D)\w\w (\d| )\d'   might be a date
'\d\d:\d\d:\d\d'            possibly the time
'.*last message repeated.*'     make this &quot;BOLD . WHITE&quot;


Use your imagination.

=head1 PREREQUISITES

Term::ANSIColor

less -R (or even -r) is nice...

=head1 BUGS

=over 4

=item * Color params are just eval()'d. You have been warned.

=item * Colorization is applied in arbitrary order, so it's not possible to guarantee the behavior of overlapping regex's...

=back

=head1 AUTHOR

A particularly demented Rob Flickenger <rob@oreillynet.com> on a late evening. Use at your own risk! Demand a refund! See where it gets you!

=head1 SEE ALSO

regex(7). No, don't look at that. Look at Camel3 or Mastering Regular Expressions in Perl...

=cut

use strict; use Term::ANSIColor qw(:constants);

my %target = ( );

while (my $arg = shift) { my $clr = shift;

if(($arg =~ /^-/) | (!$clr)) { print "Usage: rcg [regex] [color] [regex] [color] ...\n"; exit; }

Ugly, lazy, pathetic hack here

$target{$arg} = eval($clr); }

my $rst = RESET;

while(<>) { foreach my $x (keys(%target)) { s/($x)/$target{$x}$1$rst/g; } print; }

waltinator
  • 4,865