tags:

views:

200

answers:

5

How can I implement grep of Unix in Perl? I tried to use Perl's built-in grep. Here is the code which is not working:

$pattern = @ARGV[0];
$file= @ARGV[1];

open($fp,$file);

@arr = <$fp>;

@lines = grep $pattern, @arr;

close($fp);
print @lines;

And by the way, i am trying only basic grep functionality not full featured and secondly i don't want to do string parsing myself. I want to use inbuilt grep or some function of perl.

Thanks in advance :)

+9  A: 

In Perl to refer an entire array we use @. But to refer the individual elements, which are scalar we use $.

So, you need to use $ and not @ on these lines:

$pattern = @ARGV[0];
$file= @ARGV[1];

Also

this

@lines = grep $pattern, @arr;

should be

@lines = grep /$pattern/, @arr;

the grep in Perl has the general syntax of:

grep EXPR,LIST

It evaluates the EXPR for each element of LIST and returns the list value consisting of those elements for which the expression evaluated to true.

The EXPR in your case is searching for the pattern $pattern in array @arr. To search you need to use the /PATTERN/ without the / the string $pattern will be evaluated for true or false.

codaddict
@codaddict :- Thanks Got it.
Ankit Rathod
@coddadict, you did it great fixing the bugs in the code but this question and the approach used by the user converts it in a quasi 'xy problem' so this is one of those situations that indoctrination probably is not off topic. I would have recommended not to read the whole file at the same time (he wanted simulate grep that is line oriented), I would have recomended him using the grep {} instead the grep() just to create a good habit, and the three arguments open. And even further showing him the online approach (or alternatively the line by line with while) would have been a plus.
Pablo Marin-Garcia
+4  A: 

The basic "grep" functionality is already implemented. (=~)

$string =~ /pattern/;
ghostdog74
@user131527 :- Thank you!
Ankit Rathod
+8  A: 

Of course, codaddict's answer is right, but i'd like to add some remarks :

You should always begin your scripts with these two lines :

use strict;
use warnings;

Use three args open and test for errors:

open my $fh, '<', $file or die "unable to open '$file' for reading : $!";

And because of use strict you have to declare all variables. So your script will be like:

#!/usr/bin/perl

use strict;
use warnings;

my $pattern = $ARGV[0];
my $file = $ARGV[1];

open $fh, '<', $file or die "unable to open file '$file' for reading : $!";
my @arr = <$fh>;
close $fh;  # close as soon as possible

my @lines = grep /$pattern/, @arr;

print @lines;

If your file is large, you can avoid read it entirely in memory:

#!/usr/bin/perl
use strict;
use warnings;

my $pattern = qr/$ARGV[0]/;
my $file= $ARGV[1];
print "pattern=$pattern\n";

my @lines;
open my $fh, '<', $file or die "unable to open file '$file' for reading : $!";
while(my $line=<$fh>) {
    push @lines, $line if ($line =~ $pattern);
}
close($fh);
print @lines;
M42
+8  A: 

You can approximate a primitive version of grep directly on the command line. The -e option allows you to define a Perl script on the command line. The -n option wraps your script roughly like this: while (<>){ SCRIPT }.

perl -ne 'print if /PATTERN/' FILE1 FILE2 ...

A slightly better approximation of grep would prefix the file name in front of each printed match. Note that this example, like the one above, does not go through the hassle of opening any files. Instead we use Perl's <> construct to iterate through all of the files, and the $ARGV variable provides the current file name.

use strict;
use warnings;

my $pattern = shift;

while (my $line = <>){
    print $ARGV, ':', $line if $line =~ $pattern;
}
FM
+1  A: 

As you already accepted an answer, I am writing this answer for reference for future readers searching for similar problems, but not exactly yours:

As people have answered already, the way of simulating grep with perl is to use the online approach. For the use of perl as a 'better' grep (and find and cut and...) I recomend the book minimal perl and you are lucky because the chapter for 'perl as a "better" grep' is one of the sample chapters.

Here you have more examples inspired from the book:

perl -wnle '/foo/ and print' null.txt  # normal grep
perl -wnle '/foo/ and print "$ARGV: $_"' null.txt # grep -H
perl -wnle '/foo/ and print $ARGV and close ARGV' null_1.txt null_2.txt # grep -l

In the last example ARGV is the current filehandle, and as with -l you are interested in finding files with the match you can print the file name and go for the next file after the first match in a file.

Also you can search by paragraph instead by line:

$ perl -00 -wnl -e '/\bBRIBE\b/i and print;' SenQ.testimony
I knew I'd be in trouble if
I ACCEPTED THE BRIBE!
So I did not.

My minimum bribe is $100k, and she only offered me $50k,
so to preserve my pricing power, I refused it.

Or find only the first match:

$ perl -00 -wnl -e '/\bBRIBE\b/i and close ARGV;' SenQ.testimony
I knew I would be in trouble if
I ACCEPTED THE BRIBE!
So I did not.

And finally if you ask about grep and perl, I think thay I should mention ACK. It implements, in perl, the grep functionality and extend it. This is a wonderful tool and as a plus you can have it also as a CPAN package. I have always use as a command line, I don't know if you can access its methods directly from your perl programs but this would be very nice.

Pablo Marin-Garcia