BASH - Count the number of occurrences of a substring in a string












0















How can I count the number of occurrences of a substring in a string using Bash?



EXAMPLE:



I'd like to know how many times this substring...



Bluetooth
Soft blocked: no
Hard blocked: no


...occurs in this string...



0: asus-wlan: Wireless LAN
         Soft blocked: no
         Hard blocked: no
1: asus-bluetooth: Bluetooth
         Soft blocked: no
         Hard blocked: no
2: phy0: Wireless LAN
         Soft blocked: no
         Hard blocked: no
113: hci0: Bluetooth
         Soft blocked: no
         Hard blocked: no


NOTE I: I have tried several approaches with sed, grep, awk... Nothing seems to work when we have strings with spaces and multiple lines.



NOTE II: I'm a Linux user and I'm trying a solution that does not involve installing applications/tools outside those that are usually found in Linux distributions.





IMPORTANT:



I would like something like the hypothetical example below. In this case we use two Shell variables (Bash).



EXAMPLE:



STRING="0: asus-wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: asus-bluetooth: Bluetooth
Soft blocked: no
Hard blocked: no
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
113: hci0: Bluetooth
Soft blocked: no
Hard blocked: no"

SUB_STRING="Bluetooth
Soft blocked: no
Hard blocked: no"

awk -v RS='' 'NR==FNR{str=$0; next} {print gsub(str,"")}' "$STRING" "$SUB_STRING"


NOTE: We are using awk just to illustrate!










share|improve this question

























  • You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

    – juniorRubyist
    May 7 '18 at 6:06


















0















How can I count the number of occurrences of a substring in a string using Bash?



EXAMPLE:



I'd like to know how many times this substring...



Bluetooth
Soft blocked: no
Hard blocked: no


...occurs in this string...



0: asus-wlan: Wireless LAN
         Soft blocked: no
         Hard blocked: no
1: asus-bluetooth: Bluetooth
         Soft blocked: no
         Hard blocked: no
2: phy0: Wireless LAN
         Soft blocked: no
         Hard blocked: no
113: hci0: Bluetooth
         Soft blocked: no
         Hard blocked: no


NOTE I: I have tried several approaches with sed, grep, awk... Nothing seems to work when we have strings with spaces and multiple lines.



NOTE II: I'm a Linux user and I'm trying a solution that does not involve installing applications/tools outside those that are usually found in Linux distributions.





IMPORTANT:



I would like something like the hypothetical example below. In this case we use two Shell variables (Bash).



EXAMPLE:



STRING="0: asus-wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: asus-bluetooth: Bluetooth
Soft blocked: no
Hard blocked: no
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
113: hci0: Bluetooth
Soft blocked: no
Hard blocked: no"

SUB_STRING="Bluetooth
Soft blocked: no
Hard blocked: no"

awk -v RS='' 'NR==FNR{str=$0; next} {print gsub(str,"")}' "$STRING" "$SUB_STRING"


NOTE: We are using awk just to illustrate!










share|improve this question

























  • You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

    – juniorRubyist
    May 7 '18 at 6:06
















0












0








0








How can I count the number of occurrences of a substring in a string using Bash?



EXAMPLE:



I'd like to know how many times this substring...



Bluetooth
Soft blocked: no
Hard blocked: no


...occurs in this string...



0: asus-wlan: Wireless LAN
         Soft blocked: no
         Hard blocked: no
1: asus-bluetooth: Bluetooth
         Soft blocked: no
         Hard blocked: no
2: phy0: Wireless LAN
         Soft blocked: no
         Hard blocked: no
113: hci0: Bluetooth
         Soft blocked: no
         Hard blocked: no


NOTE I: I have tried several approaches with sed, grep, awk... Nothing seems to work when we have strings with spaces and multiple lines.



NOTE II: I'm a Linux user and I'm trying a solution that does not involve installing applications/tools outside those that are usually found in Linux distributions.





IMPORTANT:



I would like something like the hypothetical example below. In this case we use two Shell variables (Bash).



EXAMPLE:



STRING="0: asus-wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: asus-bluetooth: Bluetooth
Soft blocked: no
Hard blocked: no
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
113: hci0: Bluetooth
Soft blocked: no
Hard blocked: no"

SUB_STRING="Bluetooth
Soft blocked: no
Hard blocked: no"

awk -v RS='' 'NR==FNR{str=$0; next} {print gsub(str,"")}' "$STRING" "$SUB_STRING"


NOTE: We are using awk just to illustrate!










share|improve this question
















How can I count the number of occurrences of a substring in a string using Bash?



EXAMPLE:



I'd like to know how many times this substring...



Bluetooth
Soft blocked: no
Hard blocked: no


...occurs in this string...



0: asus-wlan: Wireless LAN
         Soft blocked: no
         Hard blocked: no
1: asus-bluetooth: Bluetooth
         Soft blocked: no
         Hard blocked: no
2: phy0: Wireless LAN
         Soft blocked: no
         Hard blocked: no
113: hci0: Bluetooth
         Soft blocked: no
         Hard blocked: no


NOTE I: I have tried several approaches with sed, grep, awk... Nothing seems to work when we have strings with spaces and multiple lines.



NOTE II: I'm a Linux user and I'm trying a solution that does not involve installing applications/tools outside those that are usually found in Linux distributions.





IMPORTANT:



I would like something like the hypothetical example below. In this case we use two Shell variables (Bash).



EXAMPLE:



STRING="0: asus-wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: asus-bluetooth: Bluetooth
Soft blocked: no
Hard blocked: no
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no
113: hci0: Bluetooth
Soft blocked: no
Hard blocked: no"

SUB_STRING="Bluetooth
Soft blocked: no
Hard blocked: no"

awk -v RS='' 'NR==FNR{str=$0; next} {print gsub(str,"")}' "$STRING" "$SUB_STRING"


NOTE: We are using awk just to illustrate!







bash shell shell-script bash-scripting






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 7 '18 at 16:28







Eduardo Lucio

















asked May 7 '18 at 5:03









Eduardo LucioEduardo Lucio

418726




418726













  • You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

    – juniorRubyist
    May 7 '18 at 6:06





















  • You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

    – juniorRubyist
    May 7 '18 at 6:06



















You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

– juniorRubyist
May 7 '18 at 6:06







You probably will find more help on Stack Overflow, the SE site for programmers. You could also possibly find more help on Unix & Linux SE.

– juniorRubyist
May 7 '18 at 6:06












2 Answers
2






active

oldest

votes


















2














I assume it can be done better with awk, but this is the best I can offer.



grep -zo "Bluetooths*Soft blocked: nos*Hard blocked: no" file_name | grep -c "Bluetooth"


-z makes grep treat the whole file as one line.



-o only writes the output that matched the string and not the whole line.

(in our case with -z that whould mean the whole file)



s matches blank characters and new lines.



Second instance of grep will search only for the word "Bluetooth" in the output of the first grep call.



-c makes grep write the count of matched regex, instead of the matches themself.






share|improve this answer
























  • Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

    – Eduardo Lucio
    May 7 '18 at 17:23






  • 2





    I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

    – Iskustvo
    May 7 '18 at 22:30











  • Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

    – Eduardo Lucio
    May 8 '18 at 1:14



















0














It's a bit unclear how you'd like to match (you additional example in the comment above does not shed any light), however assume that you store your string block with the network information inside a file string and the substring block inside a file substring.



Using the following approach, you'd get what I understand you expected: 2 matches.



cat string | tr -s " " | tr 'n' '@' | grep -o "$(cat substring | tr -s " " | tr 'n' '@')" | wc -l


Essentially, both strings are condensed into one line, ignoring whitespaces or tabs, and converting newlines into @. Using the grep -o syntax, we print all the occurrences (-o) of the pattern found.



However, it's unclear if in your example you expect it to match 0 times (exact positional match) or 2 times (ignoring prepended text). This is a very similar solution to what Iskustvo posted here; could it be that we misunderstood your intention?



If you're trying to count matches of a 2-dimensional text fragment, you probably need fuzzy grep.






share|improve this answer























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "3"
    };
    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%2fsuperuser.com%2fquestions%2f1320331%2fbash-count-the-number-of-occurrences-of-a-substring-in-a-string%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    I assume it can be done better with awk, but this is the best I can offer.



    grep -zo "Bluetooths*Soft blocked: nos*Hard blocked: no" file_name | grep -c "Bluetooth"


    -z makes grep treat the whole file as one line.



    -o only writes the output that matched the string and not the whole line.

    (in our case with -z that whould mean the whole file)



    s matches blank characters and new lines.



    Second instance of grep will search only for the word "Bluetooth" in the output of the first grep call.



    -c makes grep write the count of matched regex, instead of the matches themself.






    share|improve this answer
























    • Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

      – Eduardo Lucio
      May 7 '18 at 17:23






    • 2





      I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

      – Iskustvo
      May 7 '18 at 22:30











    • Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

      – Eduardo Lucio
      May 8 '18 at 1:14
















    2














    I assume it can be done better with awk, but this is the best I can offer.



    grep -zo "Bluetooths*Soft blocked: nos*Hard blocked: no" file_name | grep -c "Bluetooth"


    -z makes grep treat the whole file as one line.



    -o only writes the output that matched the string and not the whole line.

    (in our case with -z that whould mean the whole file)



    s matches blank characters and new lines.



    Second instance of grep will search only for the word "Bluetooth" in the output of the first grep call.



    -c makes grep write the count of matched regex, instead of the matches themself.






    share|improve this answer
























    • Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

      – Eduardo Lucio
      May 7 '18 at 17:23






    • 2





      I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

      – Iskustvo
      May 7 '18 at 22:30











    • Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

      – Eduardo Lucio
      May 8 '18 at 1:14














    2












    2








    2







    I assume it can be done better with awk, but this is the best I can offer.



    grep -zo "Bluetooths*Soft blocked: nos*Hard blocked: no" file_name | grep -c "Bluetooth"


    -z makes grep treat the whole file as one line.



    -o only writes the output that matched the string and not the whole line.

    (in our case with -z that whould mean the whole file)



    s matches blank characters and new lines.



    Second instance of grep will search only for the word "Bluetooth" in the output of the first grep call.



    -c makes grep write the count of matched regex, instead of the matches themself.






    share|improve this answer













    I assume it can be done better with awk, but this is the best I can offer.



    grep -zo "Bluetooths*Soft blocked: nos*Hard blocked: no" file_name | grep -c "Bluetooth"


    -z makes grep treat the whole file as one line.



    -o only writes the output that matched the string and not the whole line.

    (in our case with -z that whould mean the whole file)



    s matches blank characters and new lines.



    Second instance of grep will search only for the word "Bluetooth" in the output of the first grep call.



    -c makes grep write the count of matched regex, instead of the matches themself.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered May 7 '18 at 6:26









    IskustvoIskustvo

    5712




    5712













    • Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

      – Eduardo Lucio
      May 7 '18 at 17:23






    • 2





      I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

      – Iskustvo
      May 7 '18 at 22:30











    • Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

      – Eduardo Lucio
      May 8 '18 at 1:14



















    • Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

      – Eduardo Lucio
      May 7 '18 at 17:23






    • 2





      I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

      – Iskustvo
      May 7 '18 at 22:30











    • Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

      – Eduardo Lucio
      May 8 '18 at 1:14

















    Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

    – Eduardo Lucio
    May 7 '18 at 17:23





    Many thanks @Iskustvo, but I think there is a problem in your answer. We have to escape the string which modifies the amount of spaces and, additionally, we would have to have some functionality to automate this process. Other than that I'd like to be able to use Shell variables (Bash) (see the modification and my question)! I'll try to explain better. For example, AFAIK if my entry is " Soft blocked: no" or "Soft blocked: no" with the value "s*Soft blocked: no" match result becomes indifferent to the spaces of the original string entered. Thanks! =D

    – Eduardo Lucio
    May 7 '18 at 17:23




    2




    2





    I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

    – Iskustvo
    May 7 '18 at 22:30





    I understand what you are saying, well, not all of it, but most of it. However I don't think I'm able to provide better answer. Your request exceeds the grep and sed tools and something havier like awk, perl or python will have to be used and I can't help you with that. I hope some other answer will match all your criteria.

    – Iskustvo
    May 7 '18 at 22:30













    Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

    – Eduardo Lucio
    May 8 '18 at 1:14





    Many thanks for your contribution! Sorry for my bad English (actually I speak Portuguese)! =D

    – Eduardo Lucio
    May 8 '18 at 1:14













    0














    It's a bit unclear how you'd like to match (you additional example in the comment above does not shed any light), however assume that you store your string block with the network information inside a file string and the substring block inside a file substring.



    Using the following approach, you'd get what I understand you expected: 2 matches.



    cat string | tr -s " " | tr 'n' '@' | grep -o "$(cat substring | tr -s " " | tr 'n' '@')" | wc -l


    Essentially, both strings are condensed into one line, ignoring whitespaces or tabs, and converting newlines into @. Using the grep -o syntax, we print all the occurrences (-o) of the pattern found.



    However, it's unclear if in your example you expect it to match 0 times (exact positional match) or 2 times (ignoring prepended text). This is a very similar solution to what Iskustvo posted here; could it be that we misunderstood your intention?



    If you're trying to count matches of a 2-dimensional text fragment, you probably need fuzzy grep.






    share|improve this answer




























      0














      It's a bit unclear how you'd like to match (you additional example in the comment above does not shed any light), however assume that you store your string block with the network information inside a file string and the substring block inside a file substring.



      Using the following approach, you'd get what I understand you expected: 2 matches.



      cat string | tr -s " " | tr 'n' '@' | grep -o "$(cat substring | tr -s " " | tr 'n' '@')" | wc -l


      Essentially, both strings are condensed into one line, ignoring whitespaces or tabs, and converting newlines into @. Using the grep -o syntax, we print all the occurrences (-o) of the pattern found.



      However, it's unclear if in your example you expect it to match 0 times (exact positional match) or 2 times (ignoring prepended text). This is a very similar solution to what Iskustvo posted here; could it be that we misunderstood your intention?



      If you're trying to count matches of a 2-dimensional text fragment, you probably need fuzzy grep.






      share|improve this answer


























        0












        0








        0







        It's a bit unclear how you'd like to match (you additional example in the comment above does not shed any light), however assume that you store your string block with the network information inside a file string and the substring block inside a file substring.



        Using the following approach, you'd get what I understand you expected: 2 matches.



        cat string | tr -s " " | tr 'n' '@' | grep -o "$(cat substring | tr -s " " | tr 'n' '@')" | wc -l


        Essentially, both strings are condensed into one line, ignoring whitespaces or tabs, and converting newlines into @. Using the grep -o syntax, we print all the occurrences (-o) of the pattern found.



        However, it's unclear if in your example you expect it to match 0 times (exact positional match) or 2 times (ignoring prepended text). This is a very similar solution to what Iskustvo posted here; could it be that we misunderstood your intention?



        If you're trying to count matches of a 2-dimensional text fragment, you probably need fuzzy grep.






        share|improve this answer













        It's a bit unclear how you'd like to match (you additional example in the comment above does not shed any light), however assume that you store your string block with the network information inside a file string and the substring block inside a file substring.



        Using the following approach, you'd get what I understand you expected: 2 matches.



        cat string | tr -s " " | tr 'n' '@' | grep -o "$(cat substring | tr -s " " | tr 'n' '@')" | wc -l


        Essentially, both strings are condensed into one line, ignoring whitespaces or tabs, and converting newlines into @. Using the grep -o syntax, we print all the occurrences (-o) of the pattern found.



        However, it's unclear if in your example you expect it to match 0 times (exact positional match) or 2 times (ignoring prepended text). This is a very similar solution to what Iskustvo posted here; could it be that we misunderstood your intention?



        If you're trying to count matches of a 2-dimensional text fragment, you probably need fuzzy grep.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Feb 4 at 23:02









        MoreakiMoreaki

        546614




        546614






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Super User!


            • 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%2fsuperuser.com%2fquestions%2f1320331%2fbash-count-the-number-of-occurrences-of-a-substring-in-a-string%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

            How to make a Squid Proxy server?

            第一次世界大戦

            Touch on Surface Book