4

How do I use grep command to get part of string as below?

String:

orange:"orange", red:"apple", purple:"grape", yellow:"banana", green:"watermelon"
red:"strawberries", yellow:"lemon"

What I want:

red:"apple" yellow:"banana"
red:"strawberries" yellow:"lemon"

I have tried this:

grep -oP '(red:\"[^\"]*).*(yellow:\"[^\"]*)'
  • You can get the output red:"apple" yellow:"banana" by typing the command echo 'red:"apple" yellow:"banana"'. If you want output based on the input, specify what extraction rule you want to use. People are assuming that you want to extract the red and yellow fruits, but you haven’t said so. (Maybe you want the first and the third, or the first and the last, or every one where the color name + the fruit name add up to an even number of letters.) … (Cont’d) – G-Man Says 'Reinstate Monica' Jun 2 '19 at 23:27
  • (Cont’d) … Is the “red” fruit guaranteed to be the first one on the line? Is the “yellow” fruit guaranteed to be the last one on the line? Is there guaranteed to be exactly one between them? … … … … … … … … … … … Please do not respond in comments; edit your question to make it clearer and more complete. – G-Man Says 'Reinstate Monica' Jun 2 '19 at 23:27
4

The .* in the middle is matching everything, i.e. the purple:"grape" part. Instead (assuming you want to stick with GNU grep), I'd match each part separately with the (foo|bar) "OR" construct.

grep -oP '(red|yellow):\"[^\"]*"'

N.B. I had to add the closing ". Also, you don't need to escape the ", so you can use

grep -oP '(red|yellow):"[^"]*"'

In any case, this gives you

red:"apple"
yellow:"banana"

then to join the lines with space between them,

grep -oP '(red|yellow):"[^"]*"' | paste -sd ' ' -

Honestly, I'd naturally use sed instead.

sed -n 's/.*\(red:"[^"]*"\).*\(yellow:"[^"]*"\).*/\1 \2/p'
| improve this answer | |
  • I was faster, but you give the richer explanation so I'll delete mine – Philippos May 31 '19 at 6:40
  • @Philippos Totally up to you, but I think you are definitely justified in leaving it up! – Sparhawk May 31 '19 at 6:42
  • @Philippos And thank you for the edit; good point. – Sparhawk May 31 '19 at 6:45
2

grep does not normally extract content off lines. It prints the lines that match a regular expression (globally, it's named after the g/re/p ed command).

Some implementations like GNU grep which you seem to be using have a -o to do some of that as an extension however.

pcregrep goes even further. Its -o can take an optional numerical argument to output the content of a capture group as opposed to the whole matched portion of the line.

pcregrep -o1 -o2 --om-separator=' ' '(red:"[^"]*").*(yellow:"[^"]*")'

That's still limited in what it can do.

To extract information from the line and do more transformation, it's a text stream editor you'd want instead as others have shown here.

| improve this answer | |
1

You can indeed do it with grep as suggested by Sparhawk, or with the almost identical:

$  echo 'red:"apple", purple:"grape", yellow:"banana"' |      
        grep -oP '(red|yellow):".+?"' | perl -00pe 's/\n/ /'
red:"apple" yellow:"banana"

Personally, I'd probably do it with perl:

$ echo 'red:"apple", purple:"grape", yellow:"banana"' | 
    perl -F, -ane 'map{print if /red|yellow/}@F'
red:"apple" yellow:"banana"
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.