Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increment the last number in a string; bash

Tags:

bash

sed

awk

perl

I have a string that looks something like /foo/bar/baz59_ 5stuff.thing

I would like to increase the last number (5 in the example) by one, if it's greater than another variable. A 9 would be increased to 10. Note that the last number could be multiple digits also; also that "stuff.thing" could be anything; other than a number; so it can't be hard coded.

The above example would result in /foo/bar/baz59_ 6stuff.thing

I've found multiple questions (and answers) that would extract the last number from the string, and obviously that could then be used in a comparison. The issue I'm having is how to ensure that when I do the replace, I only replace the last number (since obviously I can't just replace "5" for "6"). Can anyone make any suggestions?

awk/sed/bash/grep are all viable.

like image 382
UKMonkey Avatar asked Jan 25 '19 14:01

UKMonkey


2 Answers

Updated Answer

Thanks to @EdMorton for pointing out the further requirement of the number exceeding a threshold. That can be done like this:

perl -spe 's/(\d+)(?!.*\d+)/$1>$thresh? $1+1 : $1/e' <<<  "abc123_456.txt" -- -thresh=500

Original Answer

You can evaluate/calculate a replacement with /e in Perl regexes. Here I just add 1 to the captured string of digits but you can do more complicated stuff:

perl -pe 's/(\d+)(?!.*\d+)/$1+1/e' <<< "abc123_456.txt"
abc123_457.txt

The (?!.*\d+) is (hopefully) a negative look-ahead for any more digits.

The $1 represents any sequence of digits captured in the capture group (\d+).

Note that this would need modification to handle decimal numbers, negative numbers and scientific notation - but that is possible.

like image 59
Mark Setchell Avatar answered Oct 13 '22 19:10

Mark Setchell


Using bash regular expression matching:

$ f="/foo/bar/baz59_ 99stuff.thing"
$ [[ $f =~ ([0-9]+)([^0-9]+)$ ]]

OK, what do we have now?

$ declare -p BASH_REMATCH
declare -ar BASH_REMATCH=([0]="99stuff.thing" [1]="99" [2]="stuff.thing")

So we can construct the new filename

if [[ $f =~ ([0-9]+)([^0-9]+)$ ]]; then
    prefix=${f%${BASH_REMATCH[0]}}           # remove "99stuff.thing" from $f
    number=$(( 10#${BASH_REMATCH[1]} + 1 ))  # use "10#" to force base10
    new=${prefix}${number}${BASH_REMATCH[2]}
    echo $new
fi
# => /foo/bar/baz59_ 100stuff.thing
like image 20
glenn jackman Avatar answered Oct 13 '22 18:10

glenn jackman