0

I have a file that looks like the following:

Pat1

Id1.1 IP1.1 Desc1.1
Id1.2 IP1.2 Desc1.2
Id1.3 IP1.3 Desc1.3
Id1.4 IP1.4 Desc1.4
Id1.5 IP1.5 Desc1.5


Pat2
Id2 IP2 Description2

Pat3
Id3 IP3 Description3

Pat4
Id4 IP4 Description4

Pat5
Id5 IP5 Description5

Pat6
Id6 IP6 Description6

and the file goes on. What I am interested in doing is extracting the IPs between Pat1 and Pat2, Pat3 and Pat4, and Pat5 and Pat6. So, the output should look like after some reformatting:

Output:

range1, IP1.1
range1, IP1.2
range1, IP1.3
range1, IP1.4
range1, IP1.5
range2, IP3
range3, IP5

I have written the following code, but I would like to shrink it by using less code to get the same output. Please take a look at the code below:

awk 'flag{ if (/Pat2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /Pat1/{flag=1}' ripe.txt > IPs.txt

awk '!/^$/' IPs.txt > IPs.csv

awk '!/[a-z]/' IPs.csv > tmp && mv tmp IPs.csv

awk '{print "range1,"$2}' IPs.csv > done.csv

awk 'flag{ if (/Pat4/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /Pat3/{flag=1}' ips.txt > A1.txt

awk '!/^$/' IPs.txt > IPs.csv

awk '!/[a-z]/' IPs.csv > tmp && mv tmp IPs.csv

awk '{print "range2,"$2}' IPs.csv >> done.csv

awk 'flag{ if (/Pat6/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /Pat5/{flag=1}' ips.txt > A1.txt

awk '!/^$/' IPs.txt > IPs.csv

awk '!/[a-z]/' IPs.csv > tmp && mv tmp IPs.csv

awk '{print "range3,"$2}' IPs.csv >> done.csv

As you see, there is a repetitive chunk of code that I would like to reduce by iterating through the patterns pairs with the flexibility of adding range1, range2, and range3 as column1 before each IP range. Thanks in advance.

AHT
  • 404
  • 1
  • 3
  • 17

1 Answers1

1

For each pattern pair Pat1, Pat2,

$ sed  '/^Pat1$/,/^Pat2$/!d;//d' input.txt | tee output.txt

Id1.1 IP1.1 Desc1.1
Id1.2 IP1.2 Desc1.2
Id1.3 IP1.3 Desc1.3
Id1.4 IP1.4 Desc1.4
Id1.5 IP1.5 Desc1.5

(Feel free to tag on a ... | grep . to omit the blank lines, filter further, etc).

You can either copy/paste & replace Pat1 and Pat2 as necessary, or use variables, which becomes an exercise in proper quoting to disable special chars while still allowing variable substitution,

a='Pat2'
b='Pat3'
sed  '/^'"${a}"'$/,/^'"${b}"'$/!d;//d' input.txt >> output.txt

Note that I'm also "appending" the additional range into output.txt (also possible via ... | tee -a output.txt, should you desire to also display the output to the console).

michael
  • 9,161
  • 2
  • 52
  • 49
  • Thanks a lot! Adding couple commands more gives the expected output. – AHT Jan 08 '18 at 08:51
  • What about if I want to pass variables from an array? (e.g. arr=(a b c d e f)) and then execute sed per each two elements. Thanks – AHT Jan 08 '18 at 09:09
  • processing pairs of variables is kind of a pain in bash, unless they have some similar base substring, e.g., `for x in a b c; do echo "${x}_1 , ${x}_2"; done` or via something using `read x y` from some input (but is tricky, if there's also output); or via two arrays with matching indices (sorry, no simple answers here) https://stackoverflow.com/questions/28725333/looping-over-pairs-of-values-in-bash https://stackoverflow.com/questions/11215088/bash-shell-script-two-variables-in-for-loop – michael Jan 08 '18 at 10:20
  • I hear you, as I tried what you just mentioned and it is not easy so to say. Thanks for the valuable info. – AHT Jan 08 '18 at 13:06