Matching pattern on multiple lines

Viewed 89

I have a file as below

NAME(BOLIVIA)              TYPE(SA)
APPLIC(Java)                 IP(192.70.xxx.xx)
NAME(BOLIVIA)              TYPE(SA)
APPLIC(Java)                 IP(192.71.xxx.xx)

I am trying to extract the values NAME and IP using sed:

cat file1  |
sed ':a
N
$!ba
s/\n/ /g' |         sed -n 's/.*\(NAME(BOLI...)\).*\(IP(.*)\).*/\1 \2/p'

However, I'm only getting the output:

NAME(BOLIVIA) IP(192.71.xxx.xx)

What I would like is:

NAME(BOLIVIA) IP(192.70.xxx.xx)
NAME(BOLIVIA) IP(192.71.xxx.xx)

Would appreciate it if someone could give me a pointer on what I'm missing.

TIA

5 Answers

In case you are ok with awk could you please try following. Written and tested in link https://ideone.com/bJDzgf with shown samples only.

awk '
match($0,/^NAME\([^)]*/){
  name=substr($0,RSTART+5,RLENGTH-5)
  next
}
match($0,/IP\([^)]*/){
  print name,substr($0,RSTART+3,RLENGTH-3)
  name=""
}
' Input_file

Your first sed commands reformats the file into one long line. You could have used tr -d "\n" for this, but that is not the problem.
The problem is in the second part, where the .* greedy eats as much as possible until finding the last match.

Your solution could be "fixed" with the ugly

# Do not use this:
sed -zn 's/[^\n]*\(NAME(BOLI...)\)[^\n]*\n[^\n]*\(IP([^)]*)\)[^\n]*/\1 \2/gp' file1

Possible solutions:

cat file1 | paste -d " " - - | sed -n 's/.*\(NAME(BOLI...)\).*\(IP(.*)\).*/\1 \2/p'
# or
grep -Eo "(NAME\(BOLI...\)|IP\(.*\))" file1 | paste -d " " - -
# or
printf "%s %s\n" $(grep -Eo "(NAME\(BOLI...\)|IP\(.*\))" file1)

This might work for you (GNU sed):

sed -n '/NAME/{N;/IP/s/\s.*\s/ /p}' file

If a line contains NAME and the following line contains IP remove everything between and print the result.

An alternative shorter awk:

awk '$1 ~ /^NAME/ {nm = $1} $2 ~ /^IP/ {print nm, $2}' file

NAME(BOLIVIA) IP(192.70.xxx.xx)
NAME(BOLIVIA) IP(192.71.xxx.xx)

The issue in your script is the use .* which matches in a greedy way so that you have only the first NAME(BOLI...) and last IP(.*)

If you can use python :

#!/bin/bash

python -c '
import re, sys
for ar in re.findall(r"(NAME\(BOLI.*?\)).*?(IP\(.*?\))", sys.stdin.read(), re.DOTALL):
    print(*ar)
' < input-file
Related