Can grep output only specified groupings that match?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












242















Say I have a file:



# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar


I only want to know what words appear after "foobar", so I can use this regex:



"foobar (w+)"


The parenthesis indicate that I have a special interest in the word right after foobar. But when I do a grep "foobar (w+)" test.txt, I get the entire lines that match the entire regex, rather than just "the word after foobar":



foobar bash 1
foobar happy


I would much prefer that the output of that command looked like this:



bash
happy


Is there a way to tell grep to only output the items that match the grouping (or a specific grouping) in a regular expression?










share|improve this question



















  • 4





    for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

    – vault
    Dec 19 '16 at 11:56















242















Say I have a file:



# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar


I only want to know what words appear after "foobar", so I can use this regex:



"foobar (w+)"


The parenthesis indicate that I have a special interest in the word right after foobar. But when I do a grep "foobar (w+)" test.txt, I get the entire lines that match the entire regex, rather than just "the word after foobar":



foobar bash 1
foobar happy


I would much prefer that the output of that command looked like this:



bash
happy


Is there a way to tell grep to only output the items that match the grouping (or a specific grouping) in a regular expression?










share|improve this question



















  • 4





    for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

    – vault
    Dec 19 '16 at 11:56













242












242








242


69






Say I have a file:



# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar


I only want to know what words appear after "foobar", so I can use this regex:



"foobar (w+)"


The parenthesis indicate that I have a special interest in the word right after foobar. But when I do a grep "foobar (w+)" test.txt, I get the entire lines that match the entire regex, rather than just "the word after foobar":



foobar bash 1
foobar happy


I would much prefer that the output of that command looked like this:



bash
happy


Is there a way to tell grep to only output the items that match the grouping (or a specific grouping) in a regular expression?










share|improve this question
















Say I have a file:



# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar


I only want to know what words appear after "foobar", so I can use this regex:



"foobar (w+)"


The parenthesis indicate that I have a special interest in the word right after foobar. But when I do a grep "foobar (w+)" test.txt, I get the entire lines that match the entire regex, rather than just "the word after foobar":



foobar bash 1
foobar happy


I would much prefer that the output of that command looked like this:



bash
happy


Is there a way to tell grep to only output the items that match the grouping (or a specific grouping) in a regular expression?







text-processing grep regular-expression






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 19 '11 at 23:17









Gilles

537k12810881605




537k12810881605










asked May 19 '11 at 23:04









Cory KleinCory Klein

5,452215983




5,452215983







  • 4





    for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

    – vault
    Dec 19 '16 at 11:56












  • 4





    for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

    – vault
    Dec 19 '16 at 11:56







4




4





for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

– vault
Dec 19 '16 at 11:56





for those who do not need grep: perl -lne 'print $1 if /foobar (w+)/' < test.txt

– vault
Dec 19 '16 at 11:56










8 Answers
8






active

oldest

votes


















282














GNU grep has the -P option for perl-style regexes, and the -o option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o.



$ grep -oP 'foobar Kw+' test.txt
bash
happy
$


The K is the short-form (and more efficient form) of (?<=pattern) which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern) can be used as a zero-width look-ahead assertion after the text you want to output.



For instance, if you wanted to match the word between foo and bar, you could use:



$ grep -oP 'foo Kw+(?= bar)' test.txt


or (for symmetry)



$ grep -oP '(?<=foo )w+(?= bar)' test.txt





share|improve this answer




















  • 2





    How you do it if your regex has more than a grouping? (as the title implied?)

    – barracel
    Mar 21 '13 at 7:52






  • 3





    @barracel: I don't believe you can. Time for sed(1)

    – camh
    Mar 22 '13 at 22:51






  • 1





    @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

    – SOUser
    Jul 24 '14 at 14:19











  • @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

    – camh
    Jul 25 '14 at 10:18











  • @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

    – rjchicago
    Dec 15 '16 at 21:40


















30














Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.



Replace foobar word other stuff by word, print only if a replacement is done.



sed -n -e 's/^foobar ([[:alnum:]]+).*/1/p'


If the first word is foobar, print the second word.



awk '$1 == "foobar" print $2'


Strip foobar if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.



perl -lne 's/^foobars+// or next; s/s.*//; print'





share|improve this answer

























  • Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

    – Cory Klein
    May 19 '11 at 23:51






  • 1





    Not true, Gilles. See my answer for a GNU grep solution.

    – camh
    May 20 '11 at 1:33






  • 1





    @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

    – Gilles
    May 20 '11 at 7:14












  • This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

    – Craig McQueen
    Mar 17 '16 at 0:12


















19














 sed -n "s/^.*foobars*(S*).*$/1/p"

-n suppress printing
s substitute
^.* anything before foobar
foobar initial search match
s* any white space character (space)
( start capture group
S* capture any non-white space character (word)
) end capture group
.*$ anything after the capture group
1 substitute everything with the 1st capture group
p print it





share|improve this answer


















  • 1





    +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

    – Tony
    May 30 '18 at 21:22


















15














Well, if you know that foobar is always the first word or the line, then you can use cut. Like so:



grep "foobar" test.file | cut -d" " -f2





share|improve this answer























  • The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

    – dubiousjim
    Apr 19 '12 at 21:04












  • I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

    – G-Man
    Apr 14 '18 at 7:20


















7














If PCRE is not supported you can achieve the same result with two invocations of grep. For example to grab the word after foobar do this:



<test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'


This can be expanded to an arbitrary word after foobar like this (with EREs for readability):



i=1
<test.txt egrep -o 'foobar +([^ ]+ +)'$i'[^ ]+' | grep -o '[^ ]*$'


Output:



1


Note the index i is zero-based.






share|improve this answer






























    4














    pcregrep has a smarter -o option
    that lets you choose which capturing groups you want output. 
    So, using your example file,



    $ pcregrep -o1 "foobar (w+)" test.txt
    bash
    happy





    share|improve this answer






























      2














      Using grep is not cross-platform compatible, since -P/--perl-regexp is only available on GNU grep, not BSD grep.



      Here is the solution using ripgrep:



      $ rg -o "foobar (w+)" -r '$1' <test.txt
      bash
      happy



      As per man rg:




      -r/--replace REPLACEMENT_TEXT Replace every match with the text given.



      Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the replacement string.




      Related: GH-462.






      share|improve this answer






























        0














        I found the answer of @jgshawkey very helpful. grep is not such a good tool for this, but sed is, although here we have an example that uses grep to grab a relevant line.



        Regex syntax of sed is idiosyncratic if you are not used to it.



        Here is another example: this one parses output of xinput to get an ID integer



        ⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]


        and I want 19



        export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=([[:digit:]]+).*$/1/p")


        Note the class syntax:



        [[:digit:]]


        and the need to escape the following +



        I assume only one line matches.






        share|improve this answer






















          Your Answer








          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "106"
          ;
          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: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          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%2funix.stackexchange.com%2fquestions%2f13466%2fcan-grep-output-only-specified-groupings-that-match%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          8 Answers
          8






          active

          oldest

          votes








          8 Answers
          8






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          282














          GNU grep has the -P option for perl-style regexes, and the -o option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o.



          $ grep -oP 'foobar Kw+' test.txt
          bash
          happy
          $


          The K is the short-form (and more efficient form) of (?<=pattern) which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern) can be used as a zero-width look-ahead assertion after the text you want to output.



          For instance, if you wanted to match the word between foo and bar, you could use:



          $ grep -oP 'foo Kw+(?= bar)' test.txt


          or (for symmetry)



          $ grep -oP '(?<=foo )w+(?= bar)' test.txt





          share|improve this answer




















          • 2





            How you do it if your regex has more than a grouping? (as the title implied?)

            – barracel
            Mar 21 '13 at 7:52






          • 3





            @barracel: I don't believe you can. Time for sed(1)

            – camh
            Mar 22 '13 at 22:51






          • 1





            @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

            – SOUser
            Jul 24 '14 at 14:19











          • @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

            – camh
            Jul 25 '14 at 10:18











          • @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

            – rjchicago
            Dec 15 '16 at 21:40















          282














          GNU grep has the -P option for perl-style regexes, and the -o option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o.



          $ grep -oP 'foobar Kw+' test.txt
          bash
          happy
          $


          The K is the short-form (and more efficient form) of (?<=pattern) which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern) can be used as a zero-width look-ahead assertion after the text you want to output.



          For instance, if you wanted to match the word between foo and bar, you could use:



          $ grep -oP 'foo Kw+(?= bar)' test.txt


          or (for symmetry)



          $ grep -oP '(?<=foo )w+(?= bar)' test.txt





          share|improve this answer




















          • 2





            How you do it if your regex has more than a grouping? (as the title implied?)

            – barracel
            Mar 21 '13 at 7:52






          • 3





            @barracel: I don't believe you can. Time for sed(1)

            – camh
            Mar 22 '13 at 22:51






          • 1





            @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

            – SOUser
            Jul 24 '14 at 14:19











          • @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

            – camh
            Jul 25 '14 at 10:18











          • @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

            – rjchicago
            Dec 15 '16 at 21:40













          282












          282








          282







          GNU grep has the -P option for perl-style regexes, and the -o option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o.



          $ grep -oP 'foobar Kw+' test.txt
          bash
          happy
          $


          The K is the short-form (and more efficient form) of (?<=pattern) which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern) can be used as a zero-width look-ahead assertion after the text you want to output.



          For instance, if you wanted to match the word between foo and bar, you could use:



          $ grep -oP 'foo Kw+(?= bar)' test.txt


          or (for symmetry)



          $ grep -oP '(?<=foo )w+(?= bar)' test.txt





          share|improve this answer















          GNU grep has the -P option for perl-style regexes, and the -o option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o.



          $ grep -oP 'foobar Kw+' test.txt
          bash
          happy
          $


          The K is the short-form (and more efficient form) of (?<=pattern) which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern) can be used as a zero-width look-ahead assertion after the text you want to output.



          For instance, if you wanted to match the word between foo and bar, you could use:



          $ grep -oP 'foo Kw+(?= bar)' test.txt


          or (for symmetry)



          $ grep -oP '(?<=foo )w+(?= bar)' test.txt






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 20 '11 at 1:50

























          answered May 20 '11 at 1:33









          camhcamh

          24.9k76352




          24.9k76352







          • 2





            How you do it if your regex has more than a grouping? (as the title implied?)

            – barracel
            Mar 21 '13 at 7:52






          • 3





            @barracel: I don't believe you can. Time for sed(1)

            – camh
            Mar 22 '13 at 22:51






          • 1





            @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

            – SOUser
            Jul 24 '14 at 14:19











          • @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

            – camh
            Jul 25 '14 at 10:18











          • @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

            – rjchicago
            Dec 15 '16 at 21:40












          • 2





            How you do it if your regex has more than a grouping? (as the title implied?)

            – barracel
            Mar 21 '13 at 7:52






          • 3





            @barracel: I don't believe you can. Time for sed(1)

            – camh
            Mar 22 '13 at 22:51






          • 1





            @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

            – SOUser
            Jul 24 '14 at 14:19











          • @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

            – camh
            Jul 25 '14 at 10:18











          • @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

            – rjchicago
            Dec 15 '16 at 21:40







          2




          2





          How you do it if your regex has more than a grouping? (as the title implied?)

          – barracel
          Mar 21 '13 at 7:52





          How you do it if your regex has more than a grouping? (as the title implied?)

          – barracel
          Mar 21 '13 at 7:52




          3




          3





          @barracel: I don't believe you can. Time for sed(1)

          – camh
          Mar 22 '13 at 22:51





          @barracel: I don't believe you can. Time for sed(1)

          – camh
          Mar 22 '13 at 22:51




          1




          1





          @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

          – SOUser
          Jul 24 '14 at 14:19





          @camh I have just tested that grep -oP 'foobar Kw+' test.txt outputs nothing with the OP's test.txt. The grep version is 2.5.1. What could be wrong ? O_O

          – SOUser
          Jul 24 '14 at 14:19













          @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

          – camh
          Jul 25 '14 at 10:18





          @XichenLi: I can't say. I just built v2.5.1 of grep (it's pretty old - from 2006) and it worked for me.

          – camh
          Jul 25 '14 at 10:18













          @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

          – rjchicago
          Dec 15 '16 at 21:40





          @SOUser: I experienced the same - outputs nothing to file. I submitted the edit request to include '>' before the filename to send output as this worked for me.

          – rjchicago
          Dec 15 '16 at 21:40













          30














          Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.



          Replace foobar word other stuff by word, print only if a replacement is done.



          sed -n -e 's/^foobar ([[:alnum:]]+).*/1/p'


          If the first word is foobar, print the second word.



          awk '$1 == "foobar" print $2'


          Strip foobar if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.



          perl -lne 's/^foobars+// or next; s/s.*//; print'





          share|improve this answer

























          • Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

            – Cory Klein
            May 19 '11 at 23:51






          • 1





            Not true, Gilles. See my answer for a GNU grep solution.

            – camh
            May 20 '11 at 1:33






          • 1





            @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

            – Gilles
            May 20 '11 at 7:14












          • This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

            – Craig McQueen
            Mar 17 '16 at 0:12















          30














          Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.



          Replace foobar word other stuff by word, print only if a replacement is done.



          sed -n -e 's/^foobar ([[:alnum:]]+).*/1/p'


          If the first word is foobar, print the second word.



          awk '$1 == "foobar" print $2'


          Strip foobar if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.



          perl -lne 's/^foobars+// or next; s/s.*//; print'





          share|improve this answer

























          • Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

            – Cory Klein
            May 19 '11 at 23:51






          • 1





            Not true, Gilles. See my answer for a GNU grep solution.

            – camh
            May 20 '11 at 1:33






          • 1





            @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

            – Gilles
            May 20 '11 at 7:14












          • This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

            – Craig McQueen
            Mar 17 '16 at 0:12













          30












          30








          30







          Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.



          Replace foobar word other stuff by word, print only if a replacement is done.



          sed -n -e 's/^foobar ([[:alnum:]]+).*/1/p'


          If the first word is foobar, print the second word.



          awk '$1 == "foobar" print $2'


          Strip foobar if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.



          perl -lne 's/^foobars+// or next; s/s.*//; print'





          share|improve this answer















          Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.



          Replace foobar word other stuff by word, print only if a replacement is done.



          sed -n -e 's/^foobar ([[:alnum:]]+).*/1/p'


          If the first word is foobar, print the second word.



          awk '$1 == "foobar" print $2'


          Strip foobar if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.



          perl -lne 's/^foobars+// or next; s/s.*//; print'






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Apr 13 '17 at 12:36









          Community

          1




          1










          answered May 19 '11 at 23:17









          GillesGilles

          537k12810881605




          537k12810881605












          • Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

            – Cory Klein
            May 19 '11 at 23:51






          • 1





            Not true, Gilles. See my answer for a GNU grep solution.

            – camh
            May 20 '11 at 1:33






          • 1





            @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

            – Gilles
            May 20 '11 at 7:14












          • This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

            – Craig McQueen
            Mar 17 '16 at 0:12

















          • Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

            – Cory Klein
            May 19 '11 at 23:51






          • 1





            Not true, Gilles. See my answer for a GNU grep solution.

            – camh
            May 20 '11 at 1:33






          • 1





            @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

            – Gilles
            May 20 '11 at 7:14












          • This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

            – Craig McQueen
            Mar 17 '16 at 0:12
















          Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

          – Cory Klein
          May 19 '11 at 23:51





          Awesome! I thought I may be able to do this with sed, but I haven't used it before and was hoping I could use my familiar grep. But the syntax for these commands actually looks very familiar now that I am familiar with vim-style search & replace + regexes. Thanks a ton.

          – Cory Klein
          May 19 '11 at 23:51




          1




          1





          Not true, Gilles. See my answer for a GNU grep solution.

          – camh
          May 20 '11 at 1:33





          Not true, Gilles. See my answer for a GNU grep solution.

          – camh
          May 20 '11 at 1:33




          1




          1





          @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

          – Gilles
          May 20 '11 at 7:14






          @camh: Ah, I didn't know GNU grep now had full PCRE support. I've corrected my answer, thanks.

          – Gilles
          May 20 '11 at 7:14














          This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

          – Craig McQueen
          Mar 17 '16 at 0:12





          This answer is especially useful for embedded Linux since Busybox grep doesn't have PCRE support.

          – Craig McQueen
          Mar 17 '16 at 0:12











          19














           sed -n "s/^.*foobars*(S*).*$/1/p"

          -n suppress printing
          s substitute
          ^.* anything before foobar
          foobar initial search match
          s* any white space character (space)
          ( start capture group
          S* capture any non-white space character (word)
          ) end capture group
          .*$ anything after the capture group
          1 substitute everything with the 1st capture group
          p print it





          share|improve this answer


















          • 1





            +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

            – Tony
            May 30 '18 at 21:22















          19














           sed -n "s/^.*foobars*(S*).*$/1/p"

          -n suppress printing
          s substitute
          ^.* anything before foobar
          foobar initial search match
          s* any white space character (space)
          ( start capture group
          S* capture any non-white space character (word)
          ) end capture group
          .*$ anything after the capture group
          1 substitute everything with the 1st capture group
          p print it





          share|improve this answer


















          • 1





            +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

            – Tony
            May 30 '18 at 21:22













          19












          19








          19







           sed -n "s/^.*foobars*(S*).*$/1/p"

          -n suppress printing
          s substitute
          ^.* anything before foobar
          foobar initial search match
          s* any white space character (space)
          ( start capture group
          S* capture any non-white space character (word)
          ) end capture group
          .*$ anything after the capture group
          1 substitute everything with the 1st capture group
          p print it





          share|improve this answer













           sed -n "s/^.*foobars*(S*).*$/1/p"

          -n suppress printing
          s substitute
          ^.* anything before foobar
          foobar initial search match
          s* any white space character (space)
          ( start capture group
          S* capture any non-white space character (word)
          ) end capture group
          .*$ anything after the capture group
          1 substitute everything with the 1st capture group
          p print it






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Apr 22 '16 at 16:08









          jgshawkeyjgshawkey

          30122




          30122







          • 1





            +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

            – Tony
            May 30 '18 at 21:22












          • 1





            +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

            – Tony
            May 30 '18 at 21:22







          1




          1





          +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

          – Tony
          May 30 '18 at 21:22





          +1 for the sed example, seems like a better tool for the job than grep. One comment, the ^ and $ are extraneous since .* is a greedy match. However, including them might help clarify the intent of the regex.

          – Tony
          May 30 '18 at 21:22











          15














          Well, if you know that foobar is always the first word or the line, then you can use cut. Like so:



          grep "foobar" test.file | cut -d" " -f2





          share|improve this answer























          • The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

            – dubiousjim
            Apr 19 '12 at 21:04












          • I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

            – G-Man
            Apr 14 '18 at 7:20















          15














          Well, if you know that foobar is always the first word or the line, then you can use cut. Like so:



          grep "foobar" test.file | cut -d" " -f2





          share|improve this answer























          • The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

            – dubiousjim
            Apr 19 '12 at 21:04












          • I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

            – G-Man
            Apr 14 '18 at 7:20













          15












          15








          15







          Well, if you know that foobar is always the first word or the line, then you can use cut. Like so:



          grep "foobar" test.file | cut -d" " -f2





          share|improve this answer













          Well, if you know that foobar is always the first word or the line, then you can use cut. Like so:



          grep "foobar" test.file | cut -d" " -f2






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered May 20 '11 at 1:07









          DaveDave

          25112




          25112












          • The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

            – dubiousjim
            Apr 19 '12 at 21:04












          • I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

            – G-Man
            Apr 14 '18 at 7:20

















          • The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

            – dubiousjim
            Apr 19 '12 at 21:04












          • I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

            – G-Man
            Apr 14 '18 at 7:20
















          The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

          – dubiousjim
          Apr 19 '12 at 21:04






          The -o switch on grep is widely implemented (moreso than the Gnu grep extensions), so doing grep -o "foobar" test.file | cut -d" " -f2 will increase the effectiveness of this solution, which is more portable than using lookbehind assertions.

          – dubiousjim
          Apr 19 '12 at 21:04














          I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

          – G-Man
          Apr 14 '18 at 7:20





          I believe that you would need grep -o "foobar .*" or grep -o "foobar w+".

          – G-Man
          Apr 14 '18 at 7:20











          7














          If PCRE is not supported you can achieve the same result with two invocations of grep. For example to grab the word after foobar do this:



          <test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'


          This can be expanded to an arbitrary word after foobar like this (with EREs for readability):



          i=1
          <test.txt egrep -o 'foobar +([^ ]+ +)'$i'[^ ]+' | grep -o '[^ ]*$'


          Output:



          1


          Note the index i is zero-based.






          share|improve this answer



























            7














            If PCRE is not supported you can achieve the same result with two invocations of grep. For example to grab the word after foobar do this:



            <test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'


            This can be expanded to an arbitrary word after foobar like this (with EREs for readability):



            i=1
            <test.txt egrep -o 'foobar +([^ ]+ +)'$i'[^ ]+' | grep -o '[^ ]*$'


            Output:



            1


            Note the index i is zero-based.






            share|improve this answer

























              7












              7








              7







              If PCRE is not supported you can achieve the same result with two invocations of grep. For example to grab the word after foobar do this:



              <test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'


              This can be expanded to an arbitrary word after foobar like this (with EREs for readability):



              i=1
              <test.txt egrep -o 'foobar +([^ ]+ +)'$i'[^ ]+' | grep -o '[^ ]*$'


              Output:



              1


              Note the index i is zero-based.






              share|improve this answer













              If PCRE is not supported you can achieve the same result with two invocations of grep. For example to grab the word after foobar do this:



              <test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'


              This can be expanded to an arbitrary word after foobar like this (with EREs for readability):



              i=1
              <test.txt egrep -o 'foobar +([^ ]+ +)'$i'[^ ]+' | grep -o '[^ ]*$'


              Output:



              1


              Note the index i is zero-based.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Oct 8 '13 at 12:38









              ThorThor

              11.8k13459




              11.8k13459





















                  4














                  pcregrep has a smarter -o option
                  that lets you choose which capturing groups you want output. 
                  So, using your example file,



                  $ pcregrep -o1 "foobar (w+)" test.txt
                  bash
                  happy





                  share|improve this answer



























                    4














                    pcregrep has a smarter -o option
                    that lets you choose which capturing groups you want output. 
                    So, using your example file,



                    $ pcregrep -o1 "foobar (w+)" test.txt
                    bash
                    happy





                    share|improve this answer

























                      4












                      4








                      4







                      pcregrep has a smarter -o option
                      that lets you choose which capturing groups you want output. 
                      So, using your example file,



                      $ pcregrep -o1 "foobar (w+)" test.txt
                      bash
                      happy





                      share|improve this answer













                      pcregrep has a smarter -o option
                      that lets you choose which capturing groups you want output. 
                      So, using your example file,



                      $ pcregrep -o1 "foobar (w+)" test.txt
                      bash
                      happy






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Apr 14 '18 at 7:29









                      G-ManG-Man

                      13.1k93465




                      13.1k93465





















                          2














                          Using grep is not cross-platform compatible, since -P/--perl-regexp is only available on GNU grep, not BSD grep.



                          Here is the solution using ripgrep:



                          $ rg -o "foobar (w+)" -r '$1' <test.txt
                          bash
                          happy



                          As per man rg:




                          -r/--replace REPLACEMENT_TEXT Replace every match with the text given.



                          Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the replacement string.




                          Related: GH-462.






                          share|improve this answer



























                            2














                            Using grep is not cross-platform compatible, since -P/--perl-regexp is only available on GNU grep, not BSD grep.



                            Here is the solution using ripgrep:



                            $ rg -o "foobar (w+)" -r '$1' <test.txt
                            bash
                            happy



                            As per man rg:




                            -r/--replace REPLACEMENT_TEXT Replace every match with the text given.



                            Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the replacement string.




                            Related: GH-462.






                            share|improve this answer

























                              2












                              2








                              2







                              Using grep is not cross-platform compatible, since -P/--perl-regexp is only available on GNU grep, not BSD grep.



                              Here is the solution using ripgrep:



                              $ rg -o "foobar (w+)" -r '$1' <test.txt
                              bash
                              happy



                              As per man rg:




                              -r/--replace REPLACEMENT_TEXT Replace every match with the text given.



                              Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the replacement string.




                              Related: GH-462.






                              share|improve this answer













                              Using grep is not cross-platform compatible, since -P/--perl-regexp is only available on GNU grep, not BSD grep.



                              Here is the solution using ripgrep:



                              $ rg -o "foobar (w+)" -r '$1' <test.txt
                              bash
                              happy



                              As per man rg:




                              -r/--replace REPLACEMENT_TEXT Replace every match with the text given.



                              Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the replacement string.




                              Related: GH-462.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Apr 16 '18 at 15:35









                              kenorbkenorb

                              8,736372108




                              8,736372108





















                                  0














                                  I found the answer of @jgshawkey very helpful. grep is not such a good tool for this, but sed is, although here we have an example that uses grep to grab a relevant line.



                                  Regex syntax of sed is idiosyncratic if you are not used to it.



                                  Here is another example: this one parses output of xinput to get an ID integer



                                  ⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]


                                  and I want 19



                                  export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=([[:digit:]]+).*$/1/p")


                                  Note the class syntax:



                                  [[:digit:]]


                                  and the need to escape the following +



                                  I assume only one line matches.






                                  share|improve this answer



























                                    0














                                    I found the answer of @jgshawkey very helpful. grep is not such a good tool for this, but sed is, although here we have an example that uses grep to grab a relevant line.



                                    Regex syntax of sed is idiosyncratic if you are not used to it.



                                    Here is another example: this one parses output of xinput to get an ID integer



                                    ⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]


                                    and I want 19



                                    export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=([[:digit:]]+).*$/1/p")


                                    Note the class syntax:



                                    [[:digit:]]


                                    and the need to escape the following +



                                    I assume only one line matches.






                                    share|improve this answer

























                                      0












                                      0








                                      0







                                      I found the answer of @jgshawkey very helpful. grep is not such a good tool for this, but sed is, although here we have an example that uses grep to grab a relevant line.



                                      Regex syntax of sed is idiosyncratic if you are not used to it.



                                      Here is another example: this one parses output of xinput to get an ID integer



                                      ⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]


                                      and I want 19



                                      export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=([[:digit:]]+).*$/1/p")


                                      Note the class syntax:



                                      [[:digit:]]


                                      and the need to escape the following +



                                      I assume only one line matches.






                                      share|improve this answer













                                      I found the answer of @jgshawkey very helpful. grep is not such a good tool for this, but sed is, although here we have an example that uses grep to grab a relevant line.



                                      Regex syntax of sed is idiosyncratic if you are not used to it.



                                      Here is another example: this one parses output of xinput to get an ID integer



                                      ⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]


                                      and I want 19



                                      export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=([[:digit:]]+).*$/1/p")


                                      Note the class syntax:



                                      [[:digit:]]


                                      and the need to escape the following +



                                      I assume only one line matches.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Jan 29 at 8:29









                                      Tim RichardsonTim Richardson

                                      1012




                                      1012



























                                          draft saved

                                          draft discarded
















































                                          Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                          • 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%2funix.stackexchange.com%2fquestions%2f13466%2fcan-grep-output-only-specified-groupings-that-match%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 check contact read email or not when send email to Individual?

                                          Displaying single band from multi-band raster using QGIS

                                          How many registers does an x86_64 CPU actually have?