ctheising98
ctheising98

Reputation: 29

Is there perl line to increment a number in a line in a file?

I have a file with one line like:

onspaces -a dataidx -p /dev/itest17/idx_dataidx20 -o 0 -s 2097150

I need to increment the number by one so the output would be:

onspaces -a dataidx -p /dev/itest17/idx_dataidx21 -o 0 -s 2097150

The could also have a line such as:

onspaces -a dataidx -p /dev/itest17/foobar01 -o 0 -s 2097150

which would result in

onspaces -a dataidx -p /dev/itest17/foobar02 -o 0 -s 2097150

I have tried

`perl -i -pe 'if ($. == 1) 
{($n) = ($m) = /([09]+)$/;
++$m;s/$n/$m/g;
} else {s/$n(?= )/$m/;}' in_file`

which was a solution to a previous question that I asked that was solved, but this one seems to be a bit different. Thanks in advance!

Note: I'm using an ancient version of Perl, 5.8.3.

Upvotes: 0

Views: 194

Answers (2)

zdim
zdim

Reputation: 66881

The only really "moving part" here is about finding the place in the line where that number is. It appears that it is the end of a path following -p

perl -pe's{\-p\s+/\S+[^0-9]\K([0-9]+)\b}{ $n = $1; ++$n }e' file

Prints as expected on the provided input. The "maneuver" with $n (instead of just 1+$1) is there to ensure that the leading zero(s) stay. To change the file in-place add -i, as in the question, after thorough testing.

This makes assumptions, since the quetion isn't very precise (for example, that paths have no spaces). It can be tweaked, and perhaps simplified, depending on requirements' details.


A brief explanation and alternatives

The /e modifier makes the replacement side be evaluated as code so we can do our math there, and what that code returns is then used as the replacement. The \K nicely "drops" everything matched up to that point, so the replcement won't touch previous matches.

However, comments clarify that this is perl v5.8.3; \K wasn't there back then (twenty years ago). Without it we have to capture everything preceding the number to change, and put it back

perl -pe's{(\-p\s+/\S+[^0-9])([0-9]+)\b}{ $n=$2; $1.(++$n) }e' file

Finally, the [^0-9] (not a digit) is there to "stop" the previous greediness of \S+, needed to match a path, so that the last number in the path can be matched in full (\S+ would only leave one digit for the final [0-9]+).


When a number is used in numeric context it can be expected to lose the leading zero(s) (ie, it normally does). However, with the auto-increment operator it doesn't if it is used as a string, and in the replacement side of a regex it is.

A trick from jhnc in a comment keeps it compact, too

perl -pe's{(\-p\s+/\S+[^0-9])\K([0-9]+)\b}{ ++($_=$1) }e' file

or, in the perl-5.8.3-has-no-\K case

perl -pe's{(\-p\s+/\S+[^0-9])([0-9]+)\b}{ $1.(++($_=$2)) }e' file

Upvotes: 2

choroba
choroba

Reputation: 241918

Similarly to the solution I provided to you previously:

perl -i~ -pe 's/([0-9]+)(?= -o)/$x = $1; ++$x/e' file

I.e. find a sequence of digits [0-9]+ followed by a space and -o (?= -o), replace the digits by the incremented number. The /e interprets the replacement as a code to run, using ++ ensures the leading zeroes are kept.

Upvotes: 3

Related Questions