Home > Mobile >  Linux grep command in Perl script not working
Linux grep command in Perl script not working

Time:08-07

I have a grep command which works on Linux command prompt: grep -Po 'rand_num=\K[^ ]*' log.txt This command prints the number after rand_num= in my log.txt file. But I need this command in perl script. I tried

my $rand_number;
$rand_number = system("grep -Po 'rand_num=\K[^ ]*' log.txt");
print "Random number = $rand_number";

But it doesn't work. I tried $rand_number = `grep -Po 'rand_num=\K[^ ]*' log.txt`; But that also didn't work

Can someone tell what is mistake here and how got get it working?

Thanks in advance.

CodePudding user response:

Once in a Perl script, there is no need to go out to the system to run an external command (that uses Perl's regex!) -- for something Perl can do really well, and really better.

Here are some ways to do this.

Open a file and read line by line, fetching the needed phrase from each line

open my $fh, '<', $file or die "Can't open $file: $!";

my @random_numbers;
while (<$fh>) { 
    push @random_numbers, /rand_num=(\S )/g;
}
close $fh;
say for @random_numbers;

or read all lines at once and pass them through a filter of sorts

open my $fh, '<', $file or die "Can't open $file: $!";

my @random_numbers = map { /rand_num=(\S )/g } <$fh>;

close $fh;
say for @random_numbers;

I use map to extract the phrase from each line, since grep would return whole lines that satisfy the condition. If there is no match an empty list is returned, "disappearing" into the overall return list from map, or into an uninitialized array if nothing whatsoever was matched. This way map acts as a filter.

The above captures the (presumed) numbers from all rand_num=NUM on each line, if there can be more than one on a line. If also presumes that the filename $file has somehow been read into the script.

Or, use the "null" filehandle (with no need for a filename)

my @random_numbers;
while (<>) { ... }                    # same block as in first example

#  OR 

my @random_numbers = map { ... } <>;  # same block as in second example

if the script is invoked with that file name on the command line, script.pl file.

This works because the "magic" diamond operator (<>) reads line by line files submitted on the command line. All of them though -- if the script runs as script.pl file1 file2 ... it will do the above through all those files.

One can also read the whole file into a string ("slurp" it) and then work with that. This is helpful when patterns of interest spread over multiple lines. Also use a library, here Path::Tiny

use Path::Tiny;  # path()

my @rn = path($file)->slurp =~ /.../g;  # same regex as before

Now the regex match is applied to the string returned by the slurp method, which contains the whole file. Since it is done in the list context, imposed on the regex by the "list" assignment, all matches are returned in a list, which is assigned to @rn.

I boldly assume that your (every) script starts with

use warnings;
use strict;

For the feature say we also need either use feature 'say'; or to use a version of Perl which includes it or another large framework which does.


The regex in the question matches all non-whitespace characters following rand_num=. If it is absolutely certain (huh) that these can only be numbers as expected, then so be it.

Otherwise, one could be more careful and use a pattern that will only match an actual number. Or, capture as above and then check that it is indeed a number, using looks_like_number from Scalar::Util

CodePudding user response:

You've found yourself trapped in quoting hell. Perl is treating the \K as an escape sequence and removing the backslash in the actual string system sees. You can double-escape the backslash if you want

system("grep -Po 'rand_num=\\K[^ ]*' log.txt");

or you can use one of Perl's myriad of ways to write a string that prohibits backslashes from expanding at all.

system q(grep -Po 'rand_num=\K[^ ]*' log.txt);

This may look weird, and if your editor isn't designed for Perl, it may not understand it either (To be honest, I'm surprised StackOverflow's code highlighter is handling it correctly). But q(...) is equivalent to '...' except that you can use single quotes inside of the former.

  • Related