Artem Kheystver
Artem Kheystver

Reputation: 23

How to use grep to output result of each line?

I have a text file with a random number of lines. Lines look like this:

neededLine [text1] sometext [text2] sometext [text3]
sometext [text4] sometext [text5] sometext [text6]
neededLine [text7] sometext [text8] sometext [text9]

I have a grep command in shell, which takes lines with 'neededLine' word, and then extracts everything inside brackets. Command looks like this: grep 'neededLine' |grep -Po '(?<=\[).*?(?=\])' | tr '\n' ' '

So my output looks like this:

text1 text2 text3 text7 text8 text9

If I remove tr, output starts with a new line for every single word:

text1 
text2 
text3
...

How do I get an output, which prints the result in one separate line for every single input line? It should look like

text1 text2 text3 
text7 text8 text9

Upvotes: 2

Views: 238

Answers (3)

oguz ismail
oguz ismail

Reputation: 50750

With sed:

sed '/neededLine/!d
s/[^[]*\[//
s/\][^[]*$//
s/\][^[]*\[/ /g' file

Upvotes: 2

RavinderSingh13
RavinderSingh13

Reputation: 133458

Could you please try following, written and tested with shown samples in GNU awk.

awk '
/neededLine/{
  while(match($0,/\[[^]]*/)){
    val=(val?val OFS:"")substr($0,RSTART+1,RLENGTH-1)
    $0=substr($0,RSTART+RLENGTH+1)
  }
  print val
  val=""
}
'  Input_file

Explanation: Adding detailed explanation for above.

awk '                                                       ##Starting awk program from here.
/neededLine/{                                               ##Checking if a line starts with neededLine then do following.
  while(match($0,/\[[^]]*/)){                               ##Using regex in match function till its result comes true in current line.
    val=(val?val OFS:"")substr($0,RSTART+1,RLENGTH-1)       ##Creating var val whose value keep concatenate its own value and its value is sub-string of current line.
    $0=substr($0,RSTART+RLENGTH+1)                          ##Assigning sub-string value to current line which will be rest of the line after matching above.
  }
  print val                                                 ##Printing val here.
  val=""                                                    ##Nullifying val here.
} 
' Input_file                                                ##Mentioning Input_file name here.

Upvotes: 2

Sundeep
Sundeep

Reputation: 23667

With perl:

$ perl -lne 'print join " ", /\[\K.*?(?=])/g if /neededLine/' ip.txt
text1 text2 text3
text7 text8 text9
  • if /neededLine/ only lines containing neededLine
  • /\[\K.*?(?=])/g extract contents between [ and ]
    • \K is helpful to discard text matched until that point
    • you can also use /\[\K[^]]+(?=])/g
  • join " " to combine the matched portions with a space
  • -l option removes the record separator and adds it back at the end of print statement, helps to get a newline character in this case


Another solution with GNU awk

$ awk -v FPAT='\\[[^]]+]' '/neededLine/{for(i=1;i<=NF;i++)
                           gsub(/^.|.$/, "", $i); print}' ip.txt
text1 text2 text3
text7 text8 text9

Upvotes: 2

Related Questions