#!/usr/bin/perl use strict; use warnings; use Term::ANSIColor; use List::Util qw( min ); use Getopt::Std; getopts( 'c:x' ); my @color = split /,/, our $opt_c || 'bold red'; @ARGV or die <<"END_USAGE"; usage: @{[ colored( 'hl [ -c colour ] [ -x ] pattern [ file... ] [ < input ]', 'bold' ) ]} You can use capturing parens in your pattern. In that case, you can supply multiple attributes separated by commas, which will be used to individually colour the submatches. @{[ colored( '-x', 'bold' ) ]} will supress lines without matches. END_USAGE my $rx = shift; $rx = qr/$rx/; while ( <> ) { s{ $rx }{ colored_match() }gex or not( our $opt_x ) or next; print; } sub colored_match { my @START = @-; my @END = @+; my $last = min( $#color, $#START ); if ( $last ) { push @START, $END[ 0 ]; push @END, $END[ 0 ]; $END[ 0 ] = $START[ 0 ]; my $str; for my $i ( 0 .. $last ) { $str .= colored( substr( $_, $START[ $i ], $END[ $i ] - $START[ $i ] ), $color[ $i ], ) unless $i == 0; $str .= colored( substr( $_, $END[ $i ], $START[ $i + 1 ] - $END[ $i ] ), $color[ 0 ], ); } return $str; } else { return colored( substr( $_, $START[ 0 ], $END[ 0 ] - $START[ 0 ] ), $color[ 0 ], ); } }