Bash string replace function similar to Javascript String.prototype.replace()











up vote
4
down vote

favorite












In JS, I can use a function String.prototype.replace() when replacing a submatch in a regular expression. For example:



var x = 'a1b2c3'.replace(/(d+)/g, (num) => {
return num*num+1
})
console.log(x)
// 'a2b5c10'


I've tried using sed but it seems that invoking an operator $(()) inside of the replacement is not possible.



$ echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/g'
# Output: a$((1*1+1))b$((2*2+1))c$((3*3+1))


Is there a similar tool or function in bash that has the functionality similar to JS's String.replace()?










share|improve this question




























    up vote
    4
    down vote

    favorite












    In JS, I can use a function String.prototype.replace() when replacing a submatch in a regular expression. For example:



    var x = 'a1b2c3'.replace(/(d+)/g, (num) => {
    return num*num+1
    })
    console.log(x)
    // 'a2b5c10'


    I've tried using sed but it seems that invoking an operator $(()) inside of the replacement is not possible.



    $ echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/g'
    # Output: a$((1*1+1))b$((2*2+1))c$((3*3+1))


    Is there a similar tool or function in bash that has the functionality similar to JS's String.replace()?










    share|improve this question


























      up vote
      4
      down vote

      favorite









      up vote
      4
      down vote

      favorite











      In JS, I can use a function String.prototype.replace() when replacing a submatch in a regular expression. For example:



      var x = 'a1b2c3'.replace(/(d+)/g, (num) => {
      return num*num+1
      })
      console.log(x)
      // 'a2b5c10'


      I've tried using sed but it seems that invoking an operator $(()) inside of the replacement is not possible.



      $ echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/g'
      # Output: a$((1*1+1))b$((2*2+1))c$((3*3+1))


      Is there a similar tool or function in bash that has the functionality similar to JS's String.replace()?










      share|improve this question















      In JS, I can use a function String.prototype.replace() when replacing a submatch in a regular expression. For example:



      var x = 'a1b2c3'.replace(/(d+)/g, (num) => {
      return num*num+1
      })
      console.log(x)
      // 'a2b5c10'


      I've tried using sed but it seems that invoking an operator $(()) inside of the replacement is not possible.



      $ echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/g'
      # Output: a$((1*1+1))b$((2*2+1))c$((3*3+1))


      Is there a similar tool or function in bash that has the functionality similar to JS's String.replace()?







      javascript bash sed sh






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 11 at 10:09

























      asked Nov 11 at 10:06









      Stanley Semilla

      354




      354
























          3 Answers
          3






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values



          str='a1b2c3'
          re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
          if [[ $str =~ $re ]]; then
          for match in "${BASH_REMATCH[@]}"; do
          final="${str/$match/$((match*match+1))}"
          done
          fi
          printf '%sn' "$final"


          The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.



          Add more capturing groups to the regex .*([0-9]+) for subsequent matches.





          If not for a pure bash solution above, using an external utility like perl, one could do it as



          perl -pe 's/d+/$&*$&+1/ge' <<<"$str"


          The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.






          share|improve this answer






























            up vote
            1
            down vote













            You can implement this in gawk using match() and substr().



            echo "a1b2c3" | awk '{
            head = ""
            tail = $0

            while (match(tail, /[0-9]+/)) {
            num = substr(tail, RSTART, RLENGTH)
            num = num * num + 1
            head = head substr(tail, 1, RSTART-1) num
            tail = substr(tail, RSTART + RLENGTH)
            }

            print head tail
            }'


            Output



            a2b5c10





            share|improve this answer






























              up vote
              0
              down vote













              I am not sure this is my favorite answer, but just to let you know GNU sed does have external command capabilities:



              echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/echo 1$((2*2+1))3/ge' | sed 's/echo //g'


              e is the trick to pass the result externally.



              The most annoying thing - echo is appended when the g and e flags are combined to the substitution groups following the first one, so the second sed gets rid of them. If someone knows if there is something built in that would be great.



              Unfortunately



              echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/ge'


              will get a working substitution but throw an error as a2b3c4 is not a command.






              share|improve this answer





















                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',
                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%2f53247642%2fbash-string-replace-function-similar-to-javascript-string-prototype-replace%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                3 Answers
                3






                active

                oldest

                votes








                3 Answers
                3






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                1
                down vote



                accepted










                The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values



                str='a1b2c3'
                re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
                if [[ $str =~ $re ]]; then
                for match in "${BASH_REMATCH[@]}"; do
                final="${str/$match/$((match*match+1))}"
                done
                fi
                printf '%sn' "$final"


                The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.



                Add more capturing groups to the regex .*([0-9]+) for subsequent matches.





                If not for a pure bash solution above, using an external utility like perl, one could do it as



                perl -pe 's/d+/$&*$&+1/ge' <<<"$str"


                The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.






                share|improve this answer



























                  up vote
                  1
                  down vote



                  accepted










                  The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values



                  str='a1b2c3'
                  re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
                  if [[ $str =~ $re ]]; then
                  for match in "${BASH_REMATCH[@]}"; do
                  final="${str/$match/$((match*match+1))}"
                  done
                  fi
                  printf '%sn' "$final"


                  The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.



                  Add more capturing groups to the regex .*([0-9]+) for subsequent matches.





                  If not for a pure bash solution above, using an external utility like perl, one could do it as



                  perl -pe 's/d+/$&*$&+1/ge' <<<"$str"


                  The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.






                  share|improve this answer

























                    up vote
                    1
                    down vote



                    accepted







                    up vote
                    1
                    down vote



                    accepted






                    The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values



                    str='a1b2c3'
                    re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
                    if [[ $str =~ $re ]]; then
                    for match in "${BASH_REMATCH[@]}"; do
                    final="${str/$match/$((match*match+1))}"
                    done
                    fi
                    printf '%sn' "$final"


                    The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.



                    Add more capturing groups to the regex .*([0-9]+) for subsequent matches.





                    If not for a pure bash solution above, using an external utility like perl, one could do it as



                    perl -pe 's/d+/$&*$&+1/ge' <<<"$str"


                    The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.






                    share|improve this answer














                    The bash shell does support a native regex operator which you can enable with the ~ flag. All you need to do is define a regex, take the captured groups and replace them with the modified values



                    str='a1b2c3'
                    re='^.*([0-9]+).*([0-9]+).*([0-9]+).*$'
                    if [[ $str =~ $re ]]; then
                    for match in "${BASH_REMATCH[@]}"; do
                    final="${str/$match/$((match*match+1))}"
                    done
                    fi
                    printf '%sn' "$final"


                    The [[ $str =~ $re ]] does the regex match and updates the captured group array ${BASH_REMATCH[@]}. So for each of the element in the order of their appearance, we do the string substitution operator ${str/old/new}. The replacement value in your case is the number multiplied with itself and added by 1.



                    Add more capturing groups to the regex .*([0-9]+) for subsequent matches.





                    If not for a pure bash solution above, using an external utility like perl, one could do it as



                    perl -pe 's/d+/$&*$&+1/ge' <<<"$str"


                    The $& refers to the captured digit in the string and the e flag allows do arithmetic operations over the captured groups.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Nov 11 at 11:35

























                    answered Nov 11 at 10:38









                    Inian

                    37.7k63669




                    37.7k63669
























                        up vote
                        1
                        down vote













                        You can implement this in gawk using match() and substr().



                        echo "a1b2c3" | awk '{
                        head = ""
                        tail = $0

                        while (match(tail, /[0-9]+/)) {
                        num = substr(tail, RSTART, RLENGTH)
                        num = num * num + 1
                        head = head substr(tail, 1, RSTART-1) num
                        tail = substr(tail, RSTART + RLENGTH)
                        }

                        print head tail
                        }'


                        Output



                        a2b5c10





                        share|improve this answer



























                          up vote
                          1
                          down vote













                          You can implement this in gawk using match() and substr().



                          echo "a1b2c3" | awk '{
                          head = ""
                          tail = $0

                          while (match(tail, /[0-9]+/)) {
                          num = substr(tail, RSTART, RLENGTH)
                          num = num * num + 1
                          head = head substr(tail, 1, RSTART-1) num
                          tail = substr(tail, RSTART + RLENGTH)
                          }

                          print head tail
                          }'


                          Output



                          a2b5c10





                          share|improve this answer

























                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote









                            You can implement this in gawk using match() and substr().



                            echo "a1b2c3" | awk '{
                            head = ""
                            tail = $0

                            while (match(tail, /[0-9]+/)) {
                            num = substr(tail, RSTART, RLENGTH)
                            num = num * num + 1
                            head = head substr(tail, 1, RSTART-1) num
                            tail = substr(tail, RSTART + RLENGTH)
                            }

                            print head tail
                            }'


                            Output



                            a2b5c10





                            share|improve this answer














                            You can implement this in gawk using match() and substr().



                            echo "a1b2c3" | awk '{
                            head = ""
                            tail = $0

                            while (match(tail, /[0-9]+/)) {
                            num = substr(tail, RSTART, RLENGTH)
                            num = num * num + 1
                            head = head substr(tail, 1, RSTART-1) num
                            tail = substr(tail, RSTART + RLENGTH)
                            }

                            print head tail
                            }'


                            Output



                            a2b5c10






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 11 at 11:02

























                            answered Nov 11 at 10:34









                            oguzismail

                            2,4741719




                            2,4741719






















                                up vote
                                0
                                down vote













                                I am not sure this is my favorite answer, but just to let you know GNU sed does have external command capabilities:



                                echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/echo 1$((2*2+1))3/ge' | sed 's/echo //g'


                                e is the trick to pass the result externally.



                                The most annoying thing - echo is appended when the g and e flags are combined to the substitution groups following the first one, so the second sed gets rid of them. If someone knows if there is something built in that would be great.



                                Unfortunately



                                echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/ge'


                                will get a working substitution but throw an error as a2b3c4 is not a command.






                                share|improve this answer

























                                  up vote
                                  0
                                  down vote













                                  I am not sure this is my favorite answer, but just to let you know GNU sed does have external command capabilities:



                                  echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/echo 1$((2*2+1))3/ge' | sed 's/echo //g'


                                  e is the trick to pass the result externally.



                                  The most annoying thing - echo is appended when the g and e flags are combined to the substitution groups following the first one, so the second sed gets rid of them. If someone knows if there is something built in that would be great.



                                  Unfortunately



                                  echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/ge'


                                  will get a working substitution but throw an error as a2b3c4 is not a command.






                                  share|improve this answer























                                    up vote
                                    0
                                    down vote










                                    up vote
                                    0
                                    down vote









                                    I am not sure this is my favorite answer, but just to let you know GNU sed does have external command capabilities:



                                    echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/echo 1$((2*2+1))3/ge' | sed 's/echo //g'


                                    e is the trick to pass the result externally.



                                    The most annoying thing - echo is appended when the g and e flags are combined to the substitution groups following the first one, so the second sed gets rid of them. If someone knows if there is something built in that would be great.



                                    Unfortunately



                                    echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/ge'


                                    will get a working substitution but throw an error as a2b3c4 is not a command.






                                    share|improve this answer












                                    I am not sure this is my favorite answer, but just to let you know GNU sed does have external command capabilities:



                                    echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/echo 1$((2*2+1))3/ge' | sed 's/echo //g'


                                    e is the trick to pass the result externally.



                                    The most annoying thing - echo is appended when the g and e flags are combined to the substitution groups following the first one, so the second sed gets rid of them. If someone knows if there is something built in that would be great.



                                    Unfortunately



                                    echo "a1b2c3" | sed 's/([^0-9]*)([0-9])([^0-9]*)/1$((2*2+1))3/ge'


                                    will get a working substitution but throw an error as a2b3c4 is not a command.







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered Nov 11 at 10:49









                                    kabanus

                                    10.8k21237




                                    10.8k21237






























                                        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.





                                        Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                        Please pay close attention to the following guidance:


                                        • 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%2f53247642%2fbash-string-replace-function-similar-to-javascript-string-prototype-replace%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

                                        Bressuire

                                        Vorschmack

                                        Quarantine