-1

There are many articles that explain how to show n lines after or before a grep match in shell.

I need a little more complicated solution: grep for a word and when it is matched I need to further grep within the next n lines. Ideally, as a result i need all the lines that matched the first search and DID NOT match the grep within the next n lines. Some sort of text search recursion.

This is not bound to grep though, any Linux/Unix tool can be used.

Sample output:

interface TenGigE0/3/0/0
 description 
 service-policy output QOS
 ipv4 mtu 1500
 ipv4 address 13.24.15.3 255.255.255.252
 carrier-delay up 3000 down 0
 load-interval 30
 dampening
!
interface TenGigE0/3/0/1
 description Link To 
!
interface TenGigE0/3/0/1.302
 description 
 vrf 1671
 ipv4 address 13.24.14.11 255.255.255.254
 encapsulation dot1q 302

I only need a list of interfaces that do not have vrf line in their config. Note that i get this output from backup database, not the router itself.

One of my clumsy ideas was to merge all the text between the word "interface" and the ! into one line and to filter out the lines that contain the word "vrf". I used awk '/^interface/,/!/' but failed to merge the output into one line.

Alex D.
  • 73
  • 9
  • interesting! But better post a sample input together with a desired output, so we all agree on the problem. – fedorqui Oct 23 '15 at 12:31
  • @fedorqui I added the sample to the main problem description. – Alex D. Oct 27 '15 at 08:46
  • You may want to read [ask] to get a better grasp on how to have a good experience here. Try to [edit] and put all the information in the question, not in comments. Also, show what you have tried and what is the expected output. Finally, accepting answers is good (you have asked many questions, accepted just a few) – fedorqui Oct 27 '15 at 09:39
  • @fedorqui Thank you for advice. – Alex D. Oct 27 '15 at 12:09

1 Answers1

1

I am absolutely certain that this could be done more efficiently, but I'm no bash wizard. Adequate kudos to this answer.

Your input.

interface TenGigE0/3/0/0
 description
 service-policy output QOS
 ipv4 mtu 1500
 ipv4 address 13.24.15.3 255.255.255.252
 carrier-delay up 3000 down 0
 load-interval 30
 dampening
!
interface TenGigE0/3/0/1
 description Link To
!
interface TenGigE0/3/0/1.302
 description
 vrf 1671
 ipv4 address 13.24.14.11 255.255.255.254
 encapsulation dot1q 302
!

Since you want all interfaces without vrf, we expect

interface TenGigE0/3/0/0
interface TenGigE0/3/0/1

This will print that output.

first_search="^interface"
second_search="vrf"
file="interface.txt"
for line in $(grep -n "$first_search" $file | sed s'/:.*//'); do
  if ! $( sed -n $line',/!/!d;p' $file \
    | grep -q $second_search ); then
    sed -n $line','$line'p' $file
  fi
done

Where $first_search is "start of the line immediately followed by 'interface'" and $second_search is just the text 'vrf'. I wrote your output to a file named "interface.txt" and assigned it to a variable.

Here's how it works. Execute each of these pieces to see how data is handed between them.

  • grep -n "$first_search" $file finds each instance of interface and prints the line number where it was found. This output is piped to...
  • sed s'/:.*//', which removes anything including and after the colon in the grep. We're left with just the line numbers where there is a match. For each of those,
  • Read the file again and remove all lines except for those between the match and "!", then print what's remaining (sed -n $line',/!/!d;p'). See the quoted answer above that details this a little better.
  • If any of these lines contain "vrf" (grep -q $second_search), do nothing. Otherwise,
  • Print the line where the original match was found with sed -n $line','$line'p' $file.

Note: I added a "!" to the end of your input because I didn't feel like toying with searching for either "!" or EOF.

Community
  • 1
  • 1
Jeremy Fortune
  • 2,459
  • 1
  • 18
  • 21
  • Could you please explain a little how this work. Will this work considering the output i have added to the question? Thank you. – Alex D. Oct 28 '15 at 07:45
  • Do you mean that your question includes the input (not the output)? If so, you indicated that you wanted to search for the same text within the next n lines, not different text. Do you want to search for "interface" and find any "vrf" lines after it? – Jeremy Fortune Oct 28 '15 at 18:05
  • Also "grep within n lines" is ambiguous. N is usually static, but the input in your question requires that N changes with each grepped value of interface. I'll try to work this up, but your question changed rather significantly. – Jeremy Fortune Oct 28 '15 at 20:37
  • Edited the answer to account for these changes. – Jeremy Fortune Oct 28 '15 at 21:23
  • Hi. Thank you for changes, now it works. See this question for a shorter solution: https://stackoverflow.com/questions/33394514/recursive-text-search-whithin-lines-before-the-grep-match-in-shell – Alex D. Oct 29 '15 at 14:15
  • I knew I should learn awk. Why did you ask your question twice? – Jeremy Fortune Oct 29 '15 at 17:07
  • I tried to ask it in a different way after discussions in this question. I thought that here it is not completely clear what exactly is needed. – Alex D. Oct 30 '15 at 08:55