Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get only the sections containing an exact element with awk

Tags:

bash

awk

I'm trying to do some text processing, but cannot figure it out, the problem is:

I have a file looks like this:

ORANGE{  
a
b
c 
CI 123  
d
e
f
g
} 

APPLE{  
1
2
3
4
5  
CI 123  
6
7  
}  

ORANGE{  
A
B
C  
CI 321  
D
E  
} 
ORANGE{
hell
CI 123
ABCD 1234
hmmm
}

awk '/ORANGE {/ {sho=1} ;/^CI 123$/ {sho=1} ;/^}$/ {sho=0} sho ' file

I tried code above but it didn't give me exactly what I wanted, instead it gives me all the ORANGE SECTIONS. I googled extensively but didn't find any related info. Thanks.

like image 494
Eason Avatar asked Dec 19 '25 05:12

Eason


2 Answers

$ cat temp 
ORANGE{  
...  
CI 123  
...
} 

APPLE{  
...  
CI 123  
...  
}  

ORANGE{  
...  
CI 321  
...  
} 
ORANGE{
...
CI 123
ABCD 1234
...
}
$ awk '/ORANGE/ {o=1;p=0} {if(o)arr[i++]=$0} /CI 123/ {if(o){for(key in arr) print arr[key];p=1}else{p=0} delete arr;i=0;next;} /}/ {if(p)print;p=0;delete arr;i=0;o=0;} o && p' temp 
ORANGE{  
...  
CI 123  
...
} 
ORANGE{
...
CI 123
ABCD 1234
...
}

Here is the same awk logic in a script file with pretty identation:

/ORANGE/ {
    o=1
    p=0
}
{
    if(o)
        arr[i++]=$0
}
/CI 123/ {
    if(o)
    {
        for(key in arr)
            print arr[key]
        p=1
    }
    else
        p=0
    delete arr
    i=0
    next
}
/}/ {
    if(p)
        print
    p=0
    delete arr
    i=0
    o=0
}
o && p

And we can use the script file like this with awk:

$ awk -f script.awk temp
ORANGE{  
...  
CI 123  
...
} 
ORANGE{
...
CI 123
ABCD 1234
...
}

Edit1: custom data

$ cat temp 
ORANGE{  
a
b
c 
CI 123  
d
e
f
g
} 

APPLE{  
1
2
3
4
5  
CI 123  
6
7  
}  

ORANGE{  
A
B
C  
CI 321  
D
E  
} 
ORANGE{
hell
CI 123
ABCD 1234
hmmm
}

$ awk '/ORANGE/ {o=1;p=0} {if(o)arr[i++]=$0} /CI 123/ {if(o){for(key in arr) print arr[key];p=1}else{p=0} delete arr;i=0;next;} /}/ {if(p)print;p=0;delete arr;i=0;o=0;} o && p' temp 
ORANGE{  
a
b
c 
CI 123  
d
e
f
g
} 
ORANGE{
hell
CI 123
ABCD 1234
hmmm
}
like image 71
riteshtch Avatar answered Dec 21 '25 01:12

riteshtch


$ awk -v RS="" '/ORANGE/&&/CI 123/' file
ORANGE{  
...  
CI 123  
...
}

Setting the AWK record separator RS to the empty string makes each block a record. Then just search with AWK for the 2 strings you want.

like image 31
user2138595 Avatar answered Dec 21 '25 02:12

user2138595