0

I am new to python and I don't seem to find why the second script does not work when using regular expressions.

Use case: I want to extract entries starting with "crypto map IPSEC xx ipsec-isakmp" from a Cisco running configuration file and print this line and the next 4. I have managed to print the lines after the match but not the matched line itself. My workaround for this is to print the text "crypto map IPSEC" statically first. The script will then print me the next 4 lines using "islice". As this is not perfect I wanted to use regular expression. This does not work at all.

>>>>>>
from itertools import islice
import re

#This works
print('Crypto map configurations: \n')
with open('show_run.txt', 'r') as f:
    for line in f:
        if 'crypto map IPSEC' and 'ipsec-isakmp' in line:
            print('crypto map IPSEC')
            print(''.join(islice(f, 4)))

f.close()

# The following does not work.
# Here I would like to use regular expressions to fetch the lines
# with "crypto map IPSEC xx ipsec-isakmp" 
#
'''
print('Crypto map configurations: \n')
with open('show_run.txt', 'r') as f:
    for line in f:
        pattern = r"crypto\smap\sIPSEC\s\d+\s.+"
        matched = re.findall(pattern, line)
        if str(matched) in line:
            print(str(matched))
            print(''.join(islice(f, 4)))
f.close()
'''
tizedboy
  • 9
  • 2
  • 1
    Your comparison is wrong. Read [how-to-test-multiple-variables-against-a-value](https://stackoverflow.com/questions/15112125/how-to-test-multiple-variables-against-a-value). Without the exact text you are matching we are unable to help. Did you try your data in http://www.regex101.com against your regular expressen? – Patrick Artner Dec 13 '19 at 13:30
  • 1
    `matched = re.findall(pattern, line)` returns a python list of strings that got matched... why ever should `if str(matched) in line:` evaluate True at any given time? – Patrick Artner Dec 13 '19 at 13:34

2 Answers2

2
if 'crypto map IPSEC' and 'ipsec-isakmp' in line:

should be:

if 'crypto map IPSEC' in line and 'ipsec-isakmp' in line:

Another alternative (if the line looks like what you described in the question):

if line.startswith('crypto map IPSEC') and line.endswith('ipsec-isakmp'): ...

And in:

print(''.join(islice(f, 4)))

You probably want to parse the line not f.

As for your question about regex: no need to parse it using a regex (consider previous parts of this answer) as it's running much slower and usually harder to maintain. That said, if this question is for learning, you can do:

import re

line = 'crypto map IPSEC 12345 ipsec-isakmp'
pattern = r'crypto map IPSEC (\d+) ipsec-isakmp'
matched = re.findall(pattern, line)
if matched:
    print(matched[0])

See repl

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • 1
    Thanks @Corsaka! according to SO community rules you should downvote an answer only if you find it not useful. The first part of my answer showed a bug. Second gave an alternative and third showed another bug. Not sure how all these were considered as "not useful" by anyone but oh well... :) – Nir Alfasi Dec 13 '19 at 13:31
  • Thank you alfasin for the critical tipp. The problem was in "if matched in line:". With this I thought I was comparing the text I am searching with the current line, but I was wrong. so just "if matched:" did the trick. https://repl.it/@TizedboyZilipen/Now-working – tizedboy Dec 13 '19 at 14:50
0

I want to extract entries starting with "crypto map IPSEC xx ipsec-isakmp" from a Cisco running configuration file and print this line and the next 4.

Then you're making it much more complicated than it has to be:

for line in f:
    if line.startswith("crypto map IPSEC") and "ipsec-isakmp" in line:
        print(line.strip())
        for i in range(4):
            try:
                print next(f).strip()
            except StopIteration:
                # we're reached the end of file and there weren't 4 lines left
                # after the last "crypto map IPSEC" line. Sh!t happens...
                break

nb: if you really insist on use regexps, replace the second line with

if re.match(r"^crypto map IPSEC \d+ ipsec-isakmp", line):

(assuming this is the correct pattern of course - hard to tell for sure without seeing your real data)

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118