Allen
Allen

Reputation: 3771

Perl Regex Command Line Issue

I'm trying to use a negative lookahead in perl in command line:

echo 1.41.1 | perl -pe "s/(?![0-9]+\.[0-9]+\.)[0-9]$/2/g"

to get an incremented version that looks like this:

1.41.2

but its just returning me:

![0-9]+\.[0-9]+\.: event not found

i've tried it in regex101 (PCRE) and it works fine, so im not sure why it doesn't work here

Upvotes: 6

Views: 655

Answers (4)

Stephen Quan
Stephen Quan

Reputation: 26309

As an alternate to lookahead, we can use capture groups, e.g. the following will capture the version number into 3 capture groups.

(\d+)\.(\d+)\.(\d+)

If you wanted to output the captured version number as is, it would be:

\1.\2.\3

And to just replace the 3rd part with the number "2" would be:

\1.\2.2

To adapt this to the OP's question, it would be:

$ echo 1.14.1 | perl -pe 's/(\d+)\.(\d+)\.(\d+)/\1.\2.2/'
1.14.2
$

Upvotes: 0

zdim
zdim

Reputation: 66964

If you want to "increment" a number then you can't hard-code the new value but need to capture what is there and increment that

echo "1.41.1" | perl -pe's/[0-9]+\.[0-9]+\.\K([0-9]+)/$1+1/e'

Here /e modifier makes it so that the replacement side is evaluated as code, and we can +1 the captured number, what is then substituted. The \K drops previous matches so we don't need to put them back; see "Lookaround Assertions" in Extended Patterns in perlre.

The lookarounds are sometimes just the thing you want, but they increase the regex complexity (just by being there), can be tricky to get right, and hurt efficiency. They aren't needed here.

The strange output you get is because the double quotes used around the Perl program "invite" the shell to look at what's inside whereby it interprets the ! as history expansion and runs that, as explained in ruakh's post.

Upvotes: 4

ruakh
ruakh

Reputation: 183564

In Bash, ! is the "history expansion character", except when escaped with a backslash or single-quotes. (Double-quotes do not disable this; that is, history expansion is supported inside double-quotes. See Difference between single and double quotes in Bash)

So, just change your double-quotes to single-quotes:

echo 1.41.1 | perl -pe 's/(?![0-9]+\.[0-9]+\.)[0-9]$/2/g'

and voilà:

1.41.2

Upvotes: 6

Emma
Emma

Reputation: 27743

I'm guessing that this expression also might work:

([0-9.]+)\.([0-9]+)

Test

perl -e'
    my $name = "1.41.1";
    $name =~ s/([0-9.]+)\.([0-9]+)/$1\.2/;
    print "$name\n";
    '

Output

1.41.2

Please see the demo here.

Upvotes: 4

Related Questions