A Perl script to match lines from files

Blue Bar separator

The following match.pl perl script can be used to display selective lines from a file or files. You can provide multiple match strings and lines matching any of the strings will be displayed. Since the strings are regular expressions you can construct an expression that will require a line to have 2 or more strings in it in order to be a match. But you are saying to yourself - I can just use grep. But grep cannot also display all lines that contain ABC but not also XYZ.

Other things you can do, make the matches caseless (default is case sensitive), display line numbers, display the matching line and a some number of following lines and display a line of dots for skipped lines.

The script will work with VOS provided that the gnu_library is installed, will work on ftLinux which has Perl installed by default and will work on ftServer provided some version of Perl is installed (I tested with ActivePerl (www.activestate.com).

Usage

perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] -match STRING [-match STRING]* [-except STRING]* -file PATH [-file PATH]* [-ouput PATH]

-lines NUMBER
Number of lines to display. the default os 1

-caseless
Indicates that the match should be caseless, the default is a case sensitive match.

-numbers
Indicates that line numbers should be printed, the default is not to print line numbers.

-dots
Indicates that a line of dots should be printed between non-continuous printed lines. The example should make it clear.

-match STRING
This is the match string. It can be a constant "foo" or a regular expression "foo.*bar". There must be at least 1 match string but there can be more. There is probably a limit by Perl is pretty flexable. I've tested it with 10. The script may print any line that matches any of the strings (see except).

-except STRING
Any line that matches one of the match strings that also matches one of the except strings is NOT printed,

-file PATH
Path to a file or files. Star names can be used. VOS ">" and "<" characters are translated into Unix style "/" and "../" characters. The Unix style is used when printing the file name. There must be at least 1 -file given but there can be more.

-output PATH
Path to an output file. If not given then STDOUT is assumed and output goes to the teminal window.

Notes:
1. With the exception of the match argument any substring of the argument string can be used, that is -e can be used for -except, -f for -file, etc. For match you must use -ma. The reason is that there is also an (undocumented) -module argument, this argument also fills in the match array I added it because so many VOS users have a "-m" abbreviation that maps to -module.

2. Arguments can be in any order.

Some examples:

The examples are from VOS but with the exception of using "/" instead of ">" to specify file names the same syntax will work. Note that program uses the "/" character when displaying the file paths.

Example 1 - your basic match
This is matching the string "case" in match.pl

perl match.pl -match case -file match.pl
********************************* match.pl *********************************    
    $minLines, $caseless, $showLineNumbers, $dots);
$caseless = 0;
                      'caseless'=> \$caseless,
   print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
           if ($caseless)
                     if ($caseless)
ready  10:23:25

Example 2 - matching multiple strings
This is matching the string "case" or "substr" in match.pl. Notice also that one -match argument preceeds the -file and the other follows it.

perl match.pl -match case -file match.pl -match substr
********************************* match.pl *********************************    
    $minLines, $caseless, $showLineNumbers, $dots);
$caseless = 0;
                      'caseless'=> \$caseless,
   print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
        print substr ($stars, 1, (75 - length ($files[$b]))/2) . " " .
              substr ($stars, 1, (75 - length ($files[$b]))/2) . "\n";
           if ($caseless)
                     if ($caseless)
ready  10:25:43

Example 3 - matching lines containg two strings
This is matching the string "if" and "case". It does required that the "case" follow the "if". You could also match on "case.*if" to make it order insensitive. I admit this doesn't case well beyond 2 order insensitive strings - but how often do you want to do that.

perl match.pl -match if.*case -file match.pl
********************************* match.pl *********************************    
           if ($caseless)
                     if ($caseless)
ready  10:29:57

Example 4 - excluding lines from the match
This is matching the string "case" but NOT "if".

perl match.pl -match case -file match.pl -except if 
********************************* match.pl *********************************    
    $minLines, $caseless, $showLineNumbers, $dots);
$caseless = 0;
                      'caseless'=> \$caseless,
   print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .

Example 5 - all lines in a file EXCEPT some, this is grep -v
The "." matches all lines and the -except excludes lines with "if"

perl match.pl -match . -file match.pl -except if
********************************* match.pl *********************************    
# match.pl begins here
#
# match.pl
# version 1.0 08-04-18
#
# Noah.Davids@stratus.com
#
# The latest version of this macro and documentation can be found at
#    http://members.cox.net/ndav1/self_published/match.html
#
use strict;
use warnings;
use Getopt::Long;
my (@match, @except, @inputFile,
    $minLines, $caseless, $showLineNumbers, $dots);
my (@files);
my ($INFILE);
my ($result, $a, $b, $i, $j, $print, $lineNumber, $lastLinePrinted, $reset);
my ($stars);
$minLines = 0;
$caseless = 0;
$showLineNumbers = 0;
--PAUSE--

Example 6 - line numbers
This is matching on case or stars but excluding if. It also adds line numbers. I also got tired of using the full argument name so everything is now 1 character. Remember that the the -m only works because I have an abbreviations that maps "-m" to "-module". Without that I would need to use "-ma" for "-match".

perl match.pl -m case -f match.pl -m stars -e if -n
********************************* match.pl *********************************
16       $minLines, $caseless, $showLineNumbers, $dots);
20   my ($stars);
23   $caseless = 0;
26   $stars = "**************************************************";
29                         'caseless'=> \$caseless,
40      print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
55           print substr ($stars, 1, (75 - length ($files[$b]))/2) . " " .
57                 substr ($stars, 1, (75 - length ($files[$b]))/2) . "\n";
ready  13:29:32

Example 7 - dots
This is the same match as example 6 but I have added the dotted lines.

perl match.pl -m case -f match.pl -m stars -e if -n -d
********************************* match.pl *********************************
                                        . . .
16       $minLines, $caseless, $showLineNumbers, $dots);
                                        . . .
20   my ($stars);
                                        . . .
23   $caseless = 0;
                                        . . .
26   $stars = "**************************************************";
                                        . . .
29                         'caseless'=> \$caseless,
                                        . . .
40      print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
                                        . . .
55           print substr ($stars, 1, (75 - length ($files[$b]))/2) . " " .
                                        . . .
57                 substr ($stars, 1, (75 - length ($files[$b]))/2) . "\n";
                                        . . .
ready  13:30:19

Example 8 - minimum number of lines
This is the same as example 7 but with a minimum line count of 2

perl match.pl -m case -f match.pl -m stars -e if -n -d -l 2
********************************* match.pl *********************************
                                        . . .
16       $minLines, $caseless, $showLineNumbers, $dots);
17   my (@files);
                                        . . .
20   my ($stars);
21
                                        . . .
23   $caseless = 0;
24   $showLineNumbers = 0;
                                        . . .
26   $stars = "**************************************************";
27
                                        . . .
29                         'caseless'=> \$caseless,
30                         'numbers' => \$showLineNumbers,
                                        . . .
40      print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
41                  "-match STRING [-match STRING]* " .
                                        . . .
55           print substr ($stars, 1, (75 - length ($files[$b]))/2) . " " .
56                 $files[$b] . " " .                                      
57                 substr ($stars, 1, (75 - length ($files[$b]))/2) . "\n";
58           open ($INFILE, $files[$b]);
                                        . . .
ready  13:31:54

Example 9 - caselessness
The first match is for "noah" and shows what it looks like when nothing matches - just the header line and a ready prompt. In the second match I have added a -c (-caseless) and I get 1 line.

perl match.pl -m noah -f match.pl                          
********************************* match.pl *********************************    
ready  11:20:40


perl match.pl -m noah -f match.pl -c
********************************* match.pl *********************************
# Noah.Davids@stratus.com
ready  11:20:44

Example 10 - multiple files using star names
This is matching for "noah" in any file ending with .pl in the current directory

perl match.pl -m noah -f *.pl -c
******************************** genpass2.pl ********************************   
********************************* match.pl *********************************
# Noah.Davids@stratus.com
*************************** packet_monitor_15.pl ***************************
******************************** pm21line.pl ********************************
********************************** test.pl **********************************
******************************** tping-v.pl ********************************
ready  11:22:53

Example 11 - multiple -f arguments with star names
This is the same match as example 10 but with 2 sets of files. The first is all *.pl in the current directory and the second is all*.pl in the testing subdirectory.

perl match.pl -m noah -f *.pl -c -f testing>*.pl
******************************** genpass2.pl ********************************   
********************************* match.pl *********************************
# Noah.Davids@stratus.com
*************************** packet_monitor_15.pl ***************************
******************************** pm21line.pl ********************************
********************************** test.pl **********************************
******************************** tping-v.pl ********************************
****************************** testing/foo.pl ******************************
$smtp->mail('noah.davids@stratus.com');
$smtp->to('noah.davids@stratus.com');
$smtp->datasend("To: noah.davids\@stratus.com\n");
$smtp->datasend("From: noah.davids\@stratus.com\n");
ready  11:26:09

Example 12 - Using an output file
This is the same match as example 10 but output is directed to the file foo.

perl match.pl -m noah -f *.pl -c -o foo                                         
ready  15:03:07
d foo

%phx_vos#m15_mas>SysAdmin>Noah_Davids>foo  08-05-20 15:03:10 mst

******************************** genpass2.pl ********************************
********************************* match.pl *********************************
# Noah.Davids@stratus.com
*************************** packet_monitor_15.pl ***************************
******************************** pm21line.pl ********************************
********************************** test.pl **********************************
******************************** tping-v.pl ********************************

ready  15:03:10

match.pl

                                                                   
# match.pl begins here                                                          
#
# match.pl
# version 1.0 08-04-18
# version 1.1 08-05-20 added output switch to send output to a file instead of
#                      terminal screen
# Noah.Davids@stratus.com
#
# The latest version of this macro and documentation can be found at
#    http://members.cox.net/ndav1/self_published/match.html
#
use strict;
use warnings;
use Getopt::Long;

my (@match, @except, @inputFile, @outputFile,
    $minLines, $caseless, $showLineNumbers, $dots);
my (@files);
my ($INFILE);
my ($result, $a, $b, $i, $j, $print, $lineNumber, $lastLinePrinted, $reset);
my ($stars);

$minLines = 0;
$caseless = 0;
$showLineNumbers = 0;
$dots = 0;
$stars = "**************************************************";

$result = GetOptions ('lines=s' => \$minLines,
                      'caseless'=> \$caseless,
                      'numbers' => \$showLineNumbers,
                      'dots'    => \$dots,
                      'match=s' => \@match,
                      'except=s'=> \@except,
                      'file=s'  => \@inputFile,
                      'module=s'=> \@match,
                      'output=s'=> \@outputFile);

if (($result != 1) || (@match == 0) || (@inputFile == 0))
   {
   print "\n\nUsage:\n";
   print "perl match.pl [-lines NUMBER] [-caseless] [-numbers] [-dots] " .
               "-match STRING [-match STRING]* " .
               "[-except STRING]* -file PATH [-file PATH]* [-output PATH]\n";
   exit;
   }     

if (!@outputFile) {open (OUT, ">&STDOUT");}
else {open (OUT, ">".$outputFile[0]) || die "Can't open outfile " . $outputFile[0];}

for ($a = 0; $a < @inputFile; $a++)
    {
    $inputFile[$a] =~ s/>/\//g;
    $inputFile[$a] =~ s/</\.\.\//g;
    @files = glob ($inputFile[$a]);
    if (@files < 1) {print OUT "\n\nNo files found for " .
                                            $inputFile[$a] . "\n\n";}
    for ($b = 0; $b < @files; $b++)
        {
        print OUT substr ($stars, 1, (75 - length ($files[$b]))/2) . " " .
              $files[$b] . " " .
              substr ($stars, 1, (75 - length ($files[$b]))/2) . "\n";
        open ($INFILE, $files[$b]);
        $lineNumber = 0;
        $lastLinePrinted = 0;
        while ($_ = <$INFILE>)
           {
           $lineNumber++;
           $print = 0;
           if ($caseless)
              {
              for ($i = 0; $i < @match; $i++) {if (/$match[$i]/i) {$print++;}}
              for ($i = 0; $i < @except; $i++) {if (/$except[$i]/i)
                    {$print = 0;}}
              }
           else
              {
              for ($i = 0; $i < @match; $i++) {if (/$match[$i]/) {$print++;}}
              for ($i = 0; $i < @except; $i++) {if (/$except[$i]/)
                    {$print = 0;}}
              }
           if ($print > 0)
              {
              if (($lastLinePrinted + 1 < $lineNumber) && $dots)
                 {print OUT "                                        . . . \n";}
              if ($showLineNumbers) {print OUT $lineNumber . "\t";}
              print OUT $_;
              $lastLinePrinted = $lineNumber;
              for ($j = 2; $j <= $minLines; $j++)
                  {
                  $_ = <$INFILE>;
                  if (defined ($_))
                     {
                     $lineNumber++;
                     if ($showLineNumbers) {print OUT $lineNumber . "\t";}
                     print OUT $_;
                     $lastLinePrinted = $lineNumber;
                     $reset = 0;
                     if ($caseless)
                        {
                         for ($i = 0; $i < @match; $i++)
                             {if (/$match[$i]/i) {$reset++;}}
                         for ($i = 0; $i < @except; $i++)
                             {if (/$except[$i]/i) {$reset = 0;}}
                         }
                     else
                        {
                         for ($i = 0; $i < @match; $i++)
                             {if (/$match[$i]/) {$reset++;}}
                         for ($i = 0; $i < @except; $i++)
                             {if (/$except[$i]/) {$reset = 0;}}
                         }
                      if ($reset > 0) {$j = 1;}
                     }
                  }
              }
           }
        if (($lastLinePrinted + 1 < $lineNumber) && $dots)
             {print OUT "                                        . . .\n";}
        close $INFILE;
        }
    }
#
# match.pl1 ends here



Blue Bar separator
This page was last modified on 08-05-20
mailbox Send comments and suggestions
to ndav1@cox.net