How to increment the last number in a string; bash












7















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.










share|improve this question




















  • 1





    If the last number is 9, what's the desired outcome? What if it's 59?

    – James Brown
    Jan 25 at 14:38






  • 1





    if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

    – UKMonkey
    Jan 25 at 14:42













  • It's always preceded by an underscore this last number of yours?

    – gboffi
    Jan 25 at 14:58











  • @gboffi no; the previous character is not fixed.

    – UKMonkey
    Jan 25 at 15:01











  • if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

    – ysth
    Jan 25 at 15:31
















7















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.










share|improve this question




















  • 1





    If the last number is 9, what's the desired outcome? What if it's 59?

    – James Brown
    Jan 25 at 14:38






  • 1





    if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

    – UKMonkey
    Jan 25 at 14:42













  • It's always preceded by an underscore this last number of yours?

    – gboffi
    Jan 25 at 14:58











  • @gboffi no; the previous character is not fixed.

    – UKMonkey
    Jan 25 at 15:01











  • if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

    – ysth
    Jan 25 at 15:31














7












7








7


1






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.










share|improve this question
















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.







bash perl awk sed






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 25 at 16:12







UKMonkey

















asked Jan 25 at 14:34









UKMonkeyUKMonkey

5,77431227




5,77431227








  • 1





    If the last number is 9, what's the desired outcome? What if it's 59?

    – James Brown
    Jan 25 at 14:38






  • 1





    if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

    – UKMonkey
    Jan 25 at 14:42













  • It's always preceded by an underscore this last number of yours?

    – gboffi
    Jan 25 at 14:58











  • @gboffi no; the previous character is not fixed.

    – UKMonkey
    Jan 25 at 15:01











  • if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

    – ysth
    Jan 25 at 15:31














  • 1





    If the last number is 9, what's the desired outcome? What if it's 59?

    – James Brown
    Jan 25 at 14:38






  • 1





    if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

    – UKMonkey
    Jan 25 at 14:42













  • It's always preceded by an underscore this last number of yours?

    – gboffi
    Jan 25 at 14:58











  • @gboffi no; the previous character is not fixed.

    – UKMonkey
    Jan 25 at 15:01











  • if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

    – ysth
    Jan 25 at 15:31








1




1





If the last number is 9, what's the desired outcome? What if it's 59?

– James Brown
Jan 25 at 14:38





If the last number is 9, what's the desired outcome? What if it's 59?

– James Brown
Jan 25 at 14:38




1




1





if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

– UKMonkey
Jan 25 at 14:42







if the last number is 9; then the desired is 10. 59; 60. 99->100 etc (question updated for posterity)

– UKMonkey
Jan 25 at 14:42















It's always preceded by an underscore this last number of yours?

– gboffi
Jan 25 at 14:58





It's always preceded by an underscore this last number of yours?

– gboffi
Jan 25 at 14:58













@gboffi no; the previous character is not fixed.

– UKMonkey
Jan 25 at 15:01





@gboffi no; the previous character is not fixed.

– UKMonkey
Jan 25 at 15:01













if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

– ysth
Jan 25 at 15:31





if it's greater than a script argument you mean the whole string, or the number? if the number, do you mean increment the last number in the string that is greater than an argument, or increment the last number in the string if it is greater than an argument?

– ysth
Jan 25 at 15:31












6 Answers
6






active

oldest

votes


















7














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.






share|improve this answer


























  • This seems to work perfectly; and even handles a string containing quotes

    – UKMonkey
    Jan 25 at 15:06






  • 5





    or s/.*(?<!d)K(d+)/$1+1/sea

    – ysth
    Jan 25 at 15:27






  • 2





    @EdMorton Well spotted! I hadn't seen that, but have added it in now.

    – Mark Setchell
    Jan 25 at 17:16






  • 1





    or s/(d+)(?=D*$)/$1+1/ea

    – Miller
    Jan 25 at 20:17











  • Thank you all for your alternative suggestions.

    – Mark Setchell
    Jan 25 at 20:55



















4














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





share|improve this answer

































    4














    With GNU awk for the 3rd arg to match():



    $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
    /foo/bar/baz59_ 6stuff.thing


    Just set t to whatever your threshold value is for incrementing, e.g.:



    $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
    /foo/bar/baz59_ 5stuff.thing





    share|improve this answer































      1















      if it's greater than a script argument.




      If I get it correctly(I am assuming you are passing an argument through a script and if its value is greater than string's 2nd field digit then increase 1 into that 2nd field's digit), could you please try following once.



      cat script.ksh
      value=$1
      echo "/foo/bar/baz59_ 5stuff.thing" |
      awk -v arg="$value" '
      match($2,/[0-9]+/){
      val=substr($2,RSTART,RLENGTH)
      val=val<arg?val+1:val
      $2=val substr($2,RSTART+RLENGTH)
      }
      1'


      Here is an example when I run script.ksh it gives following output.



      /script.ksh 7
      /foo/bar/baz59_ 6stuff.thing





      share|improve this answer


























      • @UKMonkey, could you please check this one also once and let me know if this works for you?

        – RavinderSingh13
        Jan 25 at 15:09






      • 1





        works fine! thanks

        – UKMonkey
        Jan 25 at 15:12













      • @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

        – RavinderSingh13
        Jan 25 at 15:18













      • it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

        – UKMonkey
        Jan 25 at 15:26











      • @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

        – RavinderSingh13
        Jan 25 at 15:29





















      1














      Here is a shorter gnu awk approach:



      cat incr.awk
      {
      n = split($0, a, /[0-9]+/, b)
      for(i=1; i<n; i++)
      s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
      print s a[i]
      }


      Then use it as:



      awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
      /foo/bar/baz59_ 6stuff.thing

      awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
      /foo/bar/baz59_ 80stuff.thing


      awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
      /foo/bar/baz59_ 90stuff.thing

      awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
      /foo/bar/baz59_ 80stuff.thing

      awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
      /foo/bar/stuff.thing





      share|improve this answer































        1














        An awk:



        $ echo /foo/bar/baz59_ 99stuff.thing |
        awk '
        /[0-9]/ {
        rstart=1 # keep track of the start
        while(match(substr($0,rstart),/[0-9]+/)) { # while numbers last
        rstart+=RSTART+RLENGTH-1 # increase rstart
        rlength=RLENGTH # remember length too
        }
        v=substr($0,rstart-rlength,rlength)+1 # increase last number
        print substr($0,1,rstart-rlength-1) v substr($0,rstart) # print in parts
        next
        }1' # in case there was no number
        /foo/bar/baz59_ 100stuff.thing


        Edit:



        Whoops, I missed the argument requirement (increase the last number - - by a one, if it's greater than a script argument):



        $ echo /foo/bar/baz59_ 99stuff.thing |
        awk -v arg=100 '
        /[0-9]/ {
        rstart=1
        while(match(substr($0,rstart),/[0-9]+/)) {
        rstart+=RSTART+RLENGTH-1
        rlength=RLENGTH
        }
        v=substr($0,rstart-rlength,rlength)
        if(0+v>arg) { # test if v greater that argument
        print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
        next
        }
        }1'


        Output now:



        /foo/bar/baz59_ 99stuff.thing





        share|improve this answer


























        • Updated with the script argument requirement. Missed it at first.

          – James Brown
          Jan 25 at 15:58











        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54367360%2fhow-to-increment-the-last-number-in-a-string-bash%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        7














        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.






        share|improve this answer


























        • This seems to work perfectly; and even handles a string containing quotes

          – UKMonkey
          Jan 25 at 15:06






        • 5





          or s/.*(?<!d)K(d+)/$1+1/sea

          – ysth
          Jan 25 at 15:27






        • 2





          @EdMorton Well spotted! I hadn't seen that, but have added it in now.

          – Mark Setchell
          Jan 25 at 17:16






        • 1





          or s/(d+)(?=D*$)/$1+1/ea

          – Miller
          Jan 25 at 20:17











        • Thank you all for your alternative suggestions.

          – Mark Setchell
          Jan 25 at 20:55
















        7














        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.






        share|improve this answer


























        • This seems to work perfectly; and even handles a string containing quotes

          – UKMonkey
          Jan 25 at 15:06






        • 5





          or s/.*(?<!d)K(d+)/$1+1/sea

          – ysth
          Jan 25 at 15:27






        • 2





          @EdMorton Well spotted! I hadn't seen that, but have added it in now.

          – Mark Setchell
          Jan 25 at 17:16






        • 1





          or s/(d+)(?=D*$)/$1+1/ea

          – Miller
          Jan 25 at 20:17











        • Thank you all for your alternative suggestions.

          – Mark Setchell
          Jan 25 at 20:55














        7












        7








        7







        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.






        share|improve this answer















        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 25 at 17:15

























        answered Jan 25 at 14:58









        Mark SetchellMark Setchell

        91.3k779184




        91.3k779184













        • This seems to work perfectly; and even handles a string containing quotes

          – UKMonkey
          Jan 25 at 15:06






        • 5





          or s/.*(?<!d)K(d+)/$1+1/sea

          – ysth
          Jan 25 at 15:27






        • 2





          @EdMorton Well spotted! I hadn't seen that, but have added it in now.

          – Mark Setchell
          Jan 25 at 17:16






        • 1





          or s/(d+)(?=D*$)/$1+1/ea

          – Miller
          Jan 25 at 20:17











        • Thank you all for your alternative suggestions.

          – Mark Setchell
          Jan 25 at 20:55



















        • This seems to work perfectly; and even handles a string containing quotes

          – UKMonkey
          Jan 25 at 15:06






        • 5





          or s/.*(?<!d)K(d+)/$1+1/sea

          – ysth
          Jan 25 at 15:27






        • 2





          @EdMorton Well spotted! I hadn't seen that, but have added it in now.

          – Mark Setchell
          Jan 25 at 17:16






        • 1





          or s/(d+)(?=D*$)/$1+1/ea

          – Miller
          Jan 25 at 20:17











        • Thank you all for your alternative suggestions.

          – Mark Setchell
          Jan 25 at 20:55

















        This seems to work perfectly; and even handles a string containing quotes

        – UKMonkey
        Jan 25 at 15:06





        This seems to work perfectly; and even handles a string containing quotes

        – UKMonkey
        Jan 25 at 15:06




        5




        5





        or s/.*(?<!d)K(d+)/$1+1/sea

        – ysth
        Jan 25 at 15:27





        or s/.*(?<!d)K(d+)/$1+1/sea

        – ysth
        Jan 25 at 15:27




        2




        2





        @EdMorton Well spotted! I hadn't seen that, but have added it in now.

        – Mark Setchell
        Jan 25 at 17:16





        @EdMorton Well spotted! I hadn't seen that, but have added it in now.

        – Mark Setchell
        Jan 25 at 17:16




        1




        1





        or s/(d+)(?=D*$)/$1+1/ea

        – Miller
        Jan 25 at 20:17





        or s/(d+)(?=D*$)/$1+1/ea

        – Miller
        Jan 25 at 20:17













        Thank you all for your alternative suggestions.

        – Mark Setchell
        Jan 25 at 20:55





        Thank you all for your alternative suggestions.

        – Mark Setchell
        Jan 25 at 20:55













        4














        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





        share|improve this answer






























          4














          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





          share|improve this answer




























            4












            4








            4







            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





            share|improve this answer















            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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 25 at 15:22

























            answered Jan 25 at 15:10









            glenn jackmanglenn jackman

            170k26147240




            170k26147240























                4














                With GNU awk for the 3rd arg to match():



                $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                /foo/bar/baz59_ 6stuff.thing


                Just set t to whatever your threshold value is for incrementing, e.g.:



                $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                /foo/bar/baz59_ 5stuff.thing





                share|improve this answer




























                  4














                  With GNU awk for the 3rd arg to match():



                  $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                  /foo/bar/baz59_ 6stuff.thing


                  Just set t to whatever your threshold value is for incrementing, e.g.:



                  $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                  /foo/bar/baz59_ 5stuff.thing





                  share|improve this answer


























                    4












                    4








                    4







                    With GNU awk for the 3rd arg to match():



                    $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                    /foo/bar/baz59_ 6stuff.thing


                    Just set t to whatever your threshold value is for incrementing, e.g.:



                    $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                    /foo/bar/baz59_ 5stuff.thing





                    share|improve this answer













                    With GNU awk for the 3rd arg to match():



                    $ awk -v t=3 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                    /foo/bar/baz59_ 6stuff.thing


                    Just set t to whatever your threshold value is for incrementing, e.g.:



                    $ awk -v t=7 'match($0,/(.*)([0-9]+)([^0-9]*)$/,a) && a[2]>t{a[2]++; $0=a[1] a[2] a[3]} 1' file
                    /foo/bar/baz59_ 5stuff.thing






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 25 at 16:58









                    Ed MortonEd Morton

                    111k1245102




                    111k1245102























                        1















                        if it's greater than a script argument.




                        If I get it correctly(I am assuming you are passing an argument through a script and if its value is greater than string's 2nd field digit then increase 1 into that 2nd field's digit), could you please try following once.



                        cat script.ksh
                        value=$1
                        echo "/foo/bar/baz59_ 5stuff.thing" |
                        awk -v arg="$value" '
                        match($2,/[0-9]+/){
                        val=substr($2,RSTART,RLENGTH)
                        val=val<arg?val+1:val
                        $2=val substr($2,RSTART+RLENGTH)
                        }
                        1'


                        Here is an example when I run script.ksh it gives following output.



                        /script.ksh 7
                        /foo/bar/baz59_ 6stuff.thing





                        share|improve this answer


























                        • @UKMonkey, could you please check this one also once and let me know if this works for you?

                          – RavinderSingh13
                          Jan 25 at 15:09






                        • 1





                          works fine! thanks

                          – UKMonkey
                          Jan 25 at 15:12













                        • @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                          – RavinderSingh13
                          Jan 25 at 15:18













                        • it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                          – UKMonkey
                          Jan 25 at 15:26











                        • @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                          – RavinderSingh13
                          Jan 25 at 15:29


















                        1















                        if it's greater than a script argument.




                        If I get it correctly(I am assuming you are passing an argument through a script and if its value is greater than string's 2nd field digit then increase 1 into that 2nd field's digit), could you please try following once.



                        cat script.ksh
                        value=$1
                        echo "/foo/bar/baz59_ 5stuff.thing" |
                        awk -v arg="$value" '
                        match($2,/[0-9]+/){
                        val=substr($2,RSTART,RLENGTH)
                        val=val<arg?val+1:val
                        $2=val substr($2,RSTART+RLENGTH)
                        }
                        1'


                        Here is an example when I run script.ksh it gives following output.



                        /script.ksh 7
                        /foo/bar/baz59_ 6stuff.thing





                        share|improve this answer


























                        • @UKMonkey, could you please check this one also once and let me know if this works for you?

                          – RavinderSingh13
                          Jan 25 at 15:09






                        • 1





                          works fine! thanks

                          – UKMonkey
                          Jan 25 at 15:12













                        • @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                          – RavinderSingh13
                          Jan 25 at 15:18













                        • it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                          – UKMonkey
                          Jan 25 at 15:26











                        • @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                          – RavinderSingh13
                          Jan 25 at 15:29
















                        1












                        1








                        1








                        if it's greater than a script argument.




                        If I get it correctly(I am assuming you are passing an argument through a script and if its value is greater than string's 2nd field digit then increase 1 into that 2nd field's digit), could you please try following once.



                        cat script.ksh
                        value=$1
                        echo "/foo/bar/baz59_ 5stuff.thing" |
                        awk -v arg="$value" '
                        match($2,/[0-9]+/){
                        val=substr($2,RSTART,RLENGTH)
                        val=val<arg?val+1:val
                        $2=val substr($2,RSTART+RLENGTH)
                        }
                        1'


                        Here is an example when I run script.ksh it gives following output.



                        /script.ksh 7
                        /foo/bar/baz59_ 6stuff.thing





                        share|improve this answer
















                        if it's greater than a script argument.




                        If I get it correctly(I am assuming you are passing an argument through a script and if its value is greater than string's 2nd field digit then increase 1 into that 2nd field's digit), could you please try following once.



                        cat script.ksh
                        value=$1
                        echo "/foo/bar/baz59_ 5stuff.thing" |
                        awk -v arg="$value" '
                        match($2,/[0-9]+/){
                        val=substr($2,RSTART,RLENGTH)
                        val=val<arg?val+1:val
                        $2=val substr($2,RSTART+RLENGTH)
                        }
                        1'


                        Here is an example when I run script.ksh it gives following output.



                        /script.ksh 7
                        /foo/bar/baz59_ 6stuff.thing






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jan 25 at 15:10

























                        answered Jan 25 at 14:56









                        RavinderSingh13RavinderSingh13

                        29.7k41639




                        29.7k41639













                        • @UKMonkey, could you please check this one also once and let me know if this works for you?

                          – RavinderSingh13
                          Jan 25 at 15:09






                        • 1





                          works fine! thanks

                          – UKMonkey
                          Jan 25 at 15:12













                        • @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                          – RavinderSingh13
                          Jan 25 at 15:18













                        • it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                          – UKMonkey
                          Jan 25 at 15:26











                        • @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                          – RavinderSingh13
                          Jan 25 at 15:29





















                        • @UKMonkey, could you please check this one also once and let me know if this works for you?

                          – RavinderSingh13
                          Jan 25 at 15:09






                        • 1





                          works fine! thanks

                          – UKMonkey
                          Jan 25 at 15:12













                        • @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                          – RavinderSingh13
                          Jan 25 at 15:18













                        • it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                          – UKMonkey
                          Jan 25 at 15:26











                        • @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                          – RavinderSingh13
                          Jan 25 at 15:29



















                        @UKMonkey, could you please check this one also once and let me know if this works for you?

                        – RavinderSingh13
                        Jan 25 at 15:09





                        @UKMonkey, could you please check this one also once and let me know if this works for you?

                        – RavinderSingh13
                        Jan 25 at 15:09




                        1




                        1





                        works fine! thanks

                        – UKMonkey
                        Jan 25 at 15:12







                        works fine! thanks

                        – UKMonkey
                        Jan 25 at 15:12















                        @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                        – RavinderSingh13
                        Jan 25 at 15:18







                        @UKMonkey, cool glad that it helped you, why I have specifically asked is no other solution have taken argument from script and compared it, so I wanted to make sure I understood question correctly, if you tested by passing argument then cool :)

                        – RavinderSingh13
                        Jan 25 at 15:18















                        it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                        – UKMonkey
                        Jan 25 at 15:26





                        it was the principle behind the replacement that I cared about - the full implementation such as how to plug in the string etc is a worry I didn't want to infect the question with.

                        – UKMonkey
                        Jan 25 at 15:26













                        @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                        – RavinderSingh13
                        Jan 25 at 15:29







                        @UKMonkey, well(if I get it correctly) if that is complete requirement then you need not to worry now, you have complete solution now :)

                        – RavinderSingh13
                        Jan 25 at 15:29













                        1














                        Here is a shorter gnu awk approach:



                        cat incr.awk
                        {
                        n = split($0, a, /[0-9]+/, b)
                        for(i=1; i<n; i++)
                        s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
                        print s a[i]
                        }


                        Then use it as:



                        awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
                        /foo/bar/baz59_ 6stuff.thing

                        awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
                        /foo/bar/baz59_ 80stuff.thing


                        awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
                        /foo/bar/baz59_ 90stuff.thing

                        awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
                        /foo/bar/baz59_ 80stuff.thing

                        awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
                        /foo/bar/stuff.thing





                        share|improve this answer




























                          1














                          Here is a shorter gnu awk approach:



                          cat incr.awk
                          {
                          n = split($0, a, /[0-9]+/, b)
                          for(i=1; i<n; i++)
                          s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
                          print s a[i]
                          }


                          Then use it as:



                          awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
                          /foo/bar/baz59_ 6stuff.thing

                          awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
                          /foo/bar/baz59_ 80stuff.thing


                          awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
                          /foo/bar/baz59_ 90stuff.thing

                          awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
                          /foo/bar/baz59_ 80stuff.thing

                          awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
                          /foo/bar/stuff.thing





                          share|improve this answer


























                            1












                            1








                            1







                            Here is a shorter gnu awk approach:



                            cat incr.awk
                            {
                            n = split($0, a, /[0-9]+/, b)
                            for(i=1; i<n; i++)
                            s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
                            print s a[i]
                            }


                            Then use it as:



                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
                            /foo/bar/baz59_ 6stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
                            /foo/bar/baz59_ 80stuff.thing


                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
                            /foo/bar/baz59_ 90stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
                            /foo/bar/baz59_ 80stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
                            /foo/bar/stuff.thing





                            share|improve this answer













                            Here is a shorter gnu awk approach:



                            cat incr.awk
                            {
                            n = split($0, a, /[0-9]+/, b)
                            for(i=1; i<n; i++)
                            s = s a[i] b[i] + (b[i] < max && i == n-1 ? 1 : 0)
                            print s a[i]
                            }


                            Then use it as:



                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 5stuff.thing'
                            /foo/bar/baz59_ 6stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 79stuff.thing'
                            /foo/bar/baz59_ 80stuff.thing


                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 90stuff.thing'
                            /foo/bar/baz59_ 90stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/baz59_ 80stuff.thing'
                            /foo/bar/baz59_ 80stuff.thing

                            awk -v max=80 -f incr.awk <<< '/foo/bar/stuff.thing'
                            /foo/bar/stuff.thing






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 25 at 15:28









                            anubhavaanubhava

                            531k47330407




                            531k47330407























                                1














                                An awk:



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk '
                                /[0-9]/ {
                                rstart=1 # keep track of the start
                                while(match(substr($0,rstart),/[0-9]+/)) { # while numbers last
                                rstart+=RSTART+RLENGTH-1 # increase rstart
                                rlength=RLENGTH # remember length too
                                }
                                v=substr($0,rstart-rlength,rlength)+1 # increase last number
                                print substr($0,1,rstart-rlength-1) v substr($0,rstart) # print in parts
                                next
                                }1' # in case there was no number
                                /foo/bar/baz59_ 100stuff.thing


                                Edit:



                                Whoops, I missed the argument requirement (increase the last number - - by a one, if it's greater than a script argument):



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk -v arg=100 '
                                /[0-9]/ {
                                rstart=1
                                while(match(substr($0,rstart),/[0-9]+/)) {
                                rstart+=RSTART+RLENGTH-1
                                rlength=RLENGTH
                                }
                                v=substr($0,rstart-rlength,rlength)
                                if(0+v>arg) { # test if v greater that argument
                                print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
                                next
                                }
                                }1'


                                Output now:



                                /foo/bar/baz59_ 99stuff.thing





                                share|improve this answer


























                                • Updated with the script argument requirement. Missed it at first.

                                  – James Brown
                                  Jan 25 at 15:58
















                                1














                                An awk:



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk '
                                /[0-9]/ {
                                rstart=1 # keep track of the start
                                while(match(substr($0,rstart),/[0-9]+/)) { # while numbers last
                                rstart+=RSTART+RLENGTH-1 # increase rstart
                                rlength=RLENGTH # remember length too
                                }
                                v=substr($0,rstart-rlength,rlength)+1 # increase last number
                                print substr($0,1,rstart-rlength-1) v substr($0,rstart) # print in parts
                                next
                                }1' # in case there was no number
                                /foo/bar/baz59_ 100stuff.thing


                                Edit:



                                Whoops, I missed the argument requirement (increase the last number - - by a one, if it's greater than a script argument):



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk -v arg=100 '
                                /[0-9]/ {
                                rstart=1
                                while(match(substr($0,rstart),/[0-9]+/)) {
                                rstart+=RSTART+RLENGTH-1
                                rlength=RLENGTH
                                }
                                v=substr($0,rstart-rlength,rlength)
                                if(0+v>arg) { # test if v greater that argument
                                print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
                                next
                                }
                                }1'


                                Output now:



                                /foo/bar/baz59_ 99stuff.thing





                                share|improve this answer


























                                • Updated with the script argument requirement. Missed it at first.

                                  – James Brown
                                  Jan 25 at 15:58














                                1












                                1








                                1







                                An awk:



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk '
                                /[0-9]/ {
                                rstart=1 # keep track of the start
                                while(match(substr($0,rstart),/[0-9]+/)) { # while numbers last
                                rstart+=RSTART+RLENGTH-1 # increase rstart
                                rlength=RLENGTH # remember length too
                                }
                                v=substr($0,rstart-rlength,rlength)+1 # increase last number
                                print substr($0,1,rstart-rlength-1) v substr($0,rstart) # print in parts
                                next
                                }1' # in case there was no number
                                /foo/bar/baz59_ 100stuff.thing


                                Edit:



                                Whoops, I missed the argument requirement (increase the last number - - by a one, if it's greater than a script argument):



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk -v arg=100 '
                                /[0-9]/ {
                                rstart=1
                                while(match(substr($0,rstart),/[0-9]+/)) {
                                rstart+=RSTART+RLENGTH-1
                                rlength=RLENGTH
                                }
                                v=substr($0,rstart-rlength,rlength)
                                if(0+v>arg) { # test if v greater that argument
                                print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
                                next
                                }
                                }1'


                                Output now:



                                /foo/bar/baz59_ 99stuff.thing





                                share|improve this answer















                                An awk:



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk '
                                /[0-9]/ {
                                rstart=1 # keep track of the start
                                while(match(substr($0,rstart),/[0-9]+/)) { # while numbers last
                                rstart+=RSTART+RLENGTH-1 # increase rstart
                                rlength=RLENGTH # remember length too
                                }
                                v=substr($0,rstart-rlength,rlength)+1 # increase last number
                                print substr($0,1,rstart-rlength-1) v substr($0,rstart) # print in parts
                                next
                                }1' # in case there was no number
                                /foo/bar/baz59_ 100stuff.thing


                                Edit:



                                Whoops, I missed the argument requirement (increase the last number - - by a one, if it's greater than a script argument):



                                $ echo /foo/bar/baz59_ 99stuff.thing |
                                awk -v arg=100 '
                                /[0-9]/ {
                                rstart=1
                                while(match(substr($0,rstart),/[0-9]+/)) {
                                rstart+=RSTART+RLENGTH-1
                                rlength=RLENGTH
                                }
                                v=substr($0,rstart-rlength,rlength)
                                if(0+v>arg) { # test if v greater that argument
                                print substr($0,1,rstart-rlength-1) v+1 substr($0,rstart)
                                next
                                }
                                }1'


                                Output now:



                                /foo/bar/baz59_ 99stuff.thing






                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Jan 25 at 15:56

























                                answered Jan 25 at 15:10









                                James BrownJames Brown

                                19.7k31836




                                19.7k31836













                                • Updated with the script argument requirement. Missed it at first.

                                  – James Brown
                                  Jan 25 at 15:58



















                                • Updated with the script argument requirement. Missed it at first.

                                  – James Brown
                                  Jan 25 at 15:58

















                                Updated with the script argument requirement. Missed it at first.

                                – James Brown
                                Jan 25 at 15:58





                                Updated with the script argument requirement. Missed it at first.

                                – James Brown
                                Jan 25 at 15:58


















                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54367360%2fhow-to-increment-the-last-number-in-a-string-bash%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Mario Kart Wii

                                What does “Dominus providebit” mean?

                                File:Tiny Toon Adventures Wacky Sports JP Title.png