trace out a specific character and perform the search accordingly?

Viewed 75

I am trying to look for two characters, based on the characters I want to find the remaining fields values in its subsequent line

123456Baadvvdwhbdwbdhw test1 test2 test3 test4 test5
test1 here is the test.
test2 here is the test.
here is line to skip.
here is another line to skip.
test3 here is the test.
here is another line to skip.
123415341636b121313131 test1 test2 test3 test4 test5
here is another line to skip...
here is test5 found.

condition 1st: Check if 1st field has B(until next b OR B found) then look from 2nd field on-wards if their values are present in its subsequent lines, if they are present then print them(print first line B one if at least 1 match is found)

condition 2nd: Check if 1st field has b then look for last field in all subsequent lines(until next b OR B found in both conditions), print line having b if at least 1 subsequent line has found last field as a match in it.

expected output for above shown samples will be:

123456Baadvvdwhbdwbdhw test1 test2 test3 test4 test5
test1 here is the test.
test2 here is the test.
test3 here is the test.
123415341636b121313131 test1 test2 test3 test4 test5
here is test5 found.

since I am learning scripting so I have tried this in bits and pieces like:

awk '$1 ~ "B"' file to get first field has B or not

to get fields from 2nd field to last field I used command like:

awk '{​​​​​​​for(i=2;i<=NF;i++){​​​​​​​print $i}​​​​​​​}​​​​​​​'

but I am not sure how to do it in a single awk, any guidance is highly appreciated

3 Answers

Here is an awk command that can do the job:

awk 's != "" {for (i=1; i<=NF; ++i) if (index(s, " " $i " ")) {print; next}} $1 ~ /[Bb]/ {print; $1=""; s = $0 " "}' file

123456Baadvvdwhbdwbdhw test1 test2 test3 test4 test5
test1 here is the test.
test2 here is the test.
test3 here is the test.
123415341636b121313131 test1 test2 test3 test4 test5
here is test5 found.

More readable version:

awk '
s != "" {
   for (i=1; i<=NF; ++i)
      if (index(s, " " $i " ")) {
         print
         next
      }
}
$1 ~ /[Bb]/ {
   print
   $1 = ""
   s = $0 " "
}' file

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

awk '
!NF{
  line=""
  found=count=0
  delete arr
}
index($1,"B"){
  found=1
  for(i=2;i<=NF;i++){
    arr[$i]
  }
  line=$0
  next
}
index($1,"b"){
  found=1
  arr[$NF]
  line=$0
  next
}
found{
  for(i=1;i<=NF;i++){
    if($i in arr){
      if(++count==1){ print line; line="" }
      print
      next
    }
  }
}'  Input_file

Explanation: Adding detailed explanation for above.

awk '                        ##Starting awk program from here.
!NF{                         ##Checking condition if line is empty.
  line=""                    ##Nullifying line here.
  found=count=0              ##Nullifying found and count here.
  delete arr                 ##deleting arr array here.
}
index($1,"B"){               ##Checking condition if B is found in current line.
  found=1                    ##Setting found to 1 here.
  for(i=2;i<=NF;i++){        ##Traversing through all fields from 2nd field onwards till last field.
    arr[$i]                  ##Creating arr with index of 1st field.
  }
  line=$0                    ##Setting current line value to line here.
  next                       ##next will skip all further statements from here.
}
index($1,"b"){               ##Checking if b is found in current line.
  found=1                    ##Setting found to 1 here.
  arr[$NF]                   ##Creating array arr with index of last field here.
  line=$0                    ##Setting current line value to line here.
  next                       ##next will skip all further statements from here.
}
found{                       ##Checking if found is set then do following.
  for(i=1;i<=NF;i++){        ##Traversing through all fields here.
    if($i in arr1){          ##Checking condition if current field is present in arr1 then do following.
      if(++count==1){ print line; line="" } ##Checking condition if count is 1 then print line and Nullify line here.
      print                  ##Printing current line here.
      next                   ##next will skip all further statements from here.
    }
  }
}' Input_file                ##Mentioning Input_file name here.

another awk, with header conditionally printing...

$ awk '$1~/[bB]/{delete b; p=$0; 
                 for(i=2;i<=NF;i++) b[$i]; next} 
                {for(k in b) 
                   if($0~"\\<"k"\\>") 
                     {if(p) {print p; p=""}; 
                      print; next}}' file

123456Baadvvdwhbdwbdhw test1 test2 test3 test4 test5
test1 here is the test.
test2 here is the test.
test3 here is the test.
123415341636b121313131 test1 test2 test3 test4 test5
here is test5 found.
Related