Yong
Yong

Reputation: 97

How can I extract using sed or awk between newlines after a specific pattern?

I like to check if there is other alternatives where I can print using other bash commands to get the range of IPs under #Hiko other than the below sed, tail and head which I actually figured out to get what I needed from my hosts file. I'm just curious and keen in learning more on bash, hope I could gain more knowledge from the community. :D

$ sed -n '/#Hiko/,/#Pico/p' /etc/hosts | tail -n +3 | head -n -2

/etc/hosts

#Tito

192.168.1.21
192.168.1.119

#Hiko

192.168.1.243
192.168.1.125
192.168.1.94
192.168.1.24
192.168.1.242

#Pico

192.168.1.23
192.168.1.93
192.168.1.121

Upvotes: 4

Views: 110

Answers (5)

potong
potong

Reputation: 58440

This might work for you (GNU sed):

sed -n '/^#/h;G;/^[0-9].*\n#Hiko/P' file

Copy the header to the hold buffer.

Append the hold buffer to each line.

If the line begins with a digit and contains the required header, print the first line in the pattern space.

Upvotes: 2

Sundeep
Sundeep

Reputation: 23667

With sed (checked with GNU sed, syntax might differ for other implementations)

$ sed -n '/#Hiko/{n; :a n; /^$/q; p; ba}' /etc/hosts
192.168.1.243
192.168.1.125
192.168.1.94
192.168.1.24
192.168.1.242
  • -n turn off automatic printing of pattern space
  • /#Hiko/ if line contains #Hiko
    • n get next line (assuming there's always an empty line)
    • :a label a
    • n get next line (using n will overwrite any previous content in the pattern space, so only single line content is present in this case)
    • /^$/q if the current line is empty, quit
    • p print the current line
    • ba branch to label a

Upvotes: 5

RavinderSingh13
RavinderSingh13

Reputation: 133538

1st solution: With shown samples could you please try following. Written and tested in GNU awk.

awk -v RS= '/#Pico/{exit} /#Hiko/{found=1;next} found' Input_file

Explanation:

awk -v RS= '       ##Starting awk program from here.
/#Pico/{           ##Checking condition if line has #Pico then do following.
  exit             ##exiting from program.
}
/#Hiko/{           ##Checking condition if line has #Hiko is present in line.
  found=1          ##Setting found to 1 here.
  next             ##next will skip all further statements from here.
}
found              ##Checking condition if found is SET then print the line.
' Input_file       ##mentioning Input_file name here.

2nd solution: Without using RS function try following.

awk '/#Pico/{exit} /#Hiko/{found=1;next} NF && found' Input_file

3rd solution: You could look for record #Hiko and then could print its next record and come out with shown samples.

awk -v RS= '/#Hiko/{found=1;next} found{print;exit}' Input_file

NOTE: These all solutions above check if string #Hiko or #Pico are present in anywhere in line, in case you want to look exact string then change above only /#Hiko/ and /#Pico/ part to /^#Hiko$/ and /^#Pico$/ respectively.

Upvotes: 5

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626936

You can use

awk -v RS= '/^#Hiko$/{getline;print;exit}' file
awk -v RS= '$0 == "#Hiko"{getline;print;exit}' file

Which means:

  • RS= - make awk read the file paragraph by paragraph
  • /^#Hiko$/ or '$0 == "#Hiko" - finds a paragraph that is equal to #Hiko
  • {getline;print;exit} - gets the next paragraph, prints it and exits.

See the online demo.

Upvotes: 4

anubhava
anubhava

Reputation: 785286

You may use:

awk -v RS= 'p && NR == p + 1; $1 == "#Hiko" {p = NR}' /etc/hosts

192.168.1.243
192.168.1.125
192.168.1.94
192.168.1.24
192.168.1.242

Upvotes: 3

Related Questions