foxx
foxx

Reputation: 23

printing the same field of next record after a match in awk

I'm trying to get the exact field of the next record after a match, for example, if "string1" is matched in $2 then i need to get the value of $2 of next record. i have around 100 such strings to match each occurring exactly once in an input file. but the same search string can be present in a different input file (i have more than 1000 such input files).

sample input: comma separated

10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot02,
RX RF Frequency Slot02,Channel Spacing Slot02,AMR Range (QPSK) Slot02,AMR Range (16QAM) Slot02
37740.500 [MHz],7 [MHz],Enable,Enable
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot03,
RX RF Frequency (Slot03),Channel Spacing (Slot03),AMR Range (QPSK) {(Slot03)|(SW GRP2)},AMR Range (16QAM) {(Slot03)|(SW GRP2)}
37712.500 [MHz],7 [MHz],Enable,Enable
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot04,
RX RF Frequency Slot04,Channel Spacing Slot04,AMR Range (QPSK) Slot04,AMR Range (16QAM) Slot04
,,,
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot05,
RX RF Frequency (Slot05),Channel Spacing (Slot05),AMR Range (QPSK) {(Slot05)|(SW GRP3)},AMR Range (16QAM) {(Slot05)|(SW GRP3)}

string1,string2....are search patterns contains alphanumeric with ({| in between. value fields can be empty. number of fields is not fixed. the location of string1 is not fixed. may occur in different position but will only occur once in a file.

what i tried so far:

BEGIN {
FS=OFS=","
}
{for (i=1;i<=NF;i++){
if ($i == "string1"){
    getline val;
    split(val,a,",");
    am1=a[i]}
if ($i == "string2"){
    getline val;
    split(val,a,",");
    am2=a[i]}
}
}
END {print am1,am2}

i know that this doesn't work for the given input since the i gets changed for consecutive value1 and value2. should i use different for loop for every single search string? or suggest any solution please.

for search

string1="AMR Range (QPSK) Slot02",string2="AMR Range (QPSK) {(Slot03)|(SW GRP2)}",string3="AMR Range (QPSK) Slot04",string4="AMR Range (16QAM) Slot02"

Desired output:

10.217.250.162,NTTN_EMS,Enable,Enable,,Enable

Upvotes: 0

Views: 283

Answers (2)

Ed Morton
Ed Morton

Reputation: 204015

If you're ever considering using getline be sure to first read and fully understand all the implications and caveats at http://awk.freeshell.org/AllAboutGetline

I don't understand how you get the posted expected output from the posted sample input but given this input:

$ cat strings
AMR Range (QPSK) Slot02
AMR Range (QPSK) {(Slot03)|(SW GRP2)}
AMR Range (QPSK) Slot04
AMR Range (16QAM) Slot02

$ cat file
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot02,
RX RF Frequency Slot02,Channel Spacing Slot02,AMR Range (QPSK) Slot02,AMR Range (16QAM) Slot02
37740.500 [MHz],7 [MHz],Enable,Enable
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot03,
RX RF Frequency (Slot03),Channel Spacing (Slot03),AMR Range (QPSK) {(Slot03)|(SW GRP2)},AMR Range (16QAM) {(Slot03)|(SW GRP2)}
37712.500 [MHz],7 [MHz],Enable,Enable
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot04,
RX RF Frequency Slot04,Channel Spacing Slot04,AMR Range (QPSK) Slot04,AMR Range (16QAM) Slot04
,,,
10.217.250.162,NTTN_EMS,Radio / AMR Configuration Slot05,
RX RF Frequency (Slot05),Channel Spacing (Slot05),AMR Range (QPSK) {(Slot05)|(SW GRP3)},AMR Range (16QAM) {(Slot05)|(SW GRP3)}

I think the following does what you describe in the text:

$ cat tst.awk
BEGIN { FS=OFS="," }
NR==FNR { strings[$0]; next }
FNR==1 { out = $1 OFS $2 }
{
    if (pos) {
        out = out OFS $pos
        pos = 0
    }
    for (i=1; i<=NF; i++) {
        if ($i in strings) {
            pos = i
        }
    }
}
ENDFILE {
    if (pos) {
        out = out OFS $pos
        pos = 0
    }
    print out
}

$ awk -f tst.awk strings file
10.217.250.162,NTTN_EMS,Enable,Enable,

The above uses GNU awk for ENDFILE instead of END so you can do:

awk -f tst.awk strings file1 file2 ....

or similar to handle multiple files simultaneously.

If your strings have to be hard-coded in your awk script then it's just a tweak to:

$ cat tst.awk
BEGIN {
    FS=OFS=","
    split("AMR Range (QPSK) Slot02\n\
AMR Range (QPSK) {(Slot03)|(SW GRP2)}\n\
AMR Range (QPSK) Slot04\n\
AMR Range (16QAM) Slot02", tmp, /\n/)
    for (i in tmp) {
        strings[tmp[i]]
    }
}
FNR==1 { out = $1 OFS $2 }
{
    if (pos) {
        out = out OFS $pos
        pos = 0
    }
    for (i=1; i<=NF; i++) {
        if ($i in strings) {
            pos = i
        }
    }
}
ENDFILE {
    if (pos) {
        out = out OFS $pos
        pos = 0
    }
    print out
}

$ awk -f tst.awk file
10.217.250.162,NTTN_EMS,Enable,Enable,

Upvotes: 1

karakfa
karakfa

Reputation: 67507

I didn't understand your output format but perhaps this will help. This creates the mapping of search keywords to values in the corresponding next line

Changed your last input line

$ cat file
blah,blah,blah,string1,string2,string3,blah
blah,blah,blah,value1,value2,value3,blah
string4,blah,string5,string6,blah
value4,x,value5,value6,x

and create a separate lookup file

$ cat lookup
string1
string2
string3
string4
string5
string6

and finally the script

$ awk -F, 'NR==FNR{m[$0];next} 
            FNR==1{p=$0;next}
                  {n=split(p,a); 
                   for(i=1;i<=n;i++) if(a[i] in m) print a[i],$i; 
                   p=$0}' lookup file

generates output

string1 value1
string2 value2
string3 value3
string4 value4
string5 value5
string6 value6

you can run the same script with multiple data files as well

$ awk ... lookup file1 file2 file3 ...

and perhaps add FILENAME in the print to identify which file was the source of the matches.

Upvotes: 1

Related Questions