2

I'm unable to convert Perl regex used in grep to perl syntax

#/bin/bash
string="Last logical block address=936640511 (0x37d3ffff), Number of blocks=936640512"
echo $string | grep -Po '(?<=blocks=)[^$]*'

with perl, I'm unable to succeed

#!/usr/bin/perl
my $string="Last logical block address=936640511 (0x37d3ffff), Number of blocks=936640512";
my ($blocks) = $string =~ m/(?<=blocks=)[^$]*/;
print $blocks;

Please advice if I'm using the correct regex.

2 Answers 2

5

The match operator in list context returns the captured texts if there are any, so all you need to do is add a capture (parens) around the bit you want returned.

my ($blocks) = $string =~ /(?<=blocks=)([^$]*)/;
print "$blocks\n";

The lookbehind is just slowing you down.

my ($blocks) = $string =~ /blocks=([^$]*)/;
print "$blocks\n";

We should check if the match actually succeeded.

if ( my ($blocks) = $string =~ /blocks=([^$]+)/ ) {
    print "$blocks\n";
}

But I'm confused as to why you're matching characters other than the dollar sign. You probably meant to match characters other than the newline.

if ( my ($blocks) = $string =~ /blocks=([^\n]+)/ ) {
    print "$blocks\n";
}

Given that you aren't using /s, that can also be written

if ( my ($blocks) = $string =~ /blocks=(.+)/ ) {
    print "$blocks\n";
}

Personally, I'd use

if ( my ($blocks) = $string =~ /blocks=(\S+)/ ) {
    print "$blocks\n";
}

To get all matches, it's just a question of using /g.

for my $blocks ( $string =~ /blocks=(\S+)/g ) {
    print "$blocks\n";
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks ikegami. But in truth both answers are failing as my $string is a multiline output - Read Capacity results: Last logical block address=936640511 (0x37d3ffff), Number of blocks=936640512 Logical block length=512 bytes Hence: Device size: 479559942144 bytes, 457344 MiB, 479.56 GB
Thanks ikegami!! I have obtained the required output.
1

The [^$] pattern matches "anything except a literal $", not end-of-string as you intended.

Try this instead:

if ($str =~ m/(?<=blocks=)(.*)$/)
{
    my $blocks = $1;
    print $blocks;
}

You can also print $& which is a special variable (man perlvar) corresponding to the last matched string. Then you don't need to use the () capture or $1.

7 Comments

Thanks. I now understand the meaning of =~, but I tried the above snippet and I see only a blank. Does this mean match was failure?
ug, don't use $&. It slows down every regex match without captures in your program.
@dvnrrs, while you are right about the 2nd point (regex) your first point is wrong. OP is doing the match in list context and hence $blocks would contain the matched value. Check the section under 'Matching in list context' in the perldoc perlop page.
@sateesh Thanks; removed that from the answer. @ikegami Regarding $1 vs. $& I'll leave it as-is since I present both options without taking a stance on which is better.
Mentioning it at all is taking a stance that it's acceptable, but you should never use $&.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.