Limiting arrays and using lindex in regexp commands

Answered Question
Apr 6th, 2012
User Badges:

Hello there,


Here's my second and extremely crap question/post with regards to EEM/TCL.  I've been doing some googling and haven't really been able to find an answer to these questions.  Probably more due to my lack of skill with the search bar than the information just not being out there.  Hope you'll forgive me though.


1.     My first question is this.  Say I want to get some output from a command.  I'd like to see all the interfaces in the "show ip vrf interface command" for example.  Not knowing how many interfaces there might be, there could be 10 or there could be 200, what's the best way of limiting a loop function after I have issued the following commands?


set _vrf_int [exec show ip vrf interface]
set _array_vrf_int [split $_vrf_int "\n"]

set $i 0

while {$i < 200} {
  regexp {([A-Z]+[a-z]+[0-9]+).*} [lindex $_array_vrf_int $i] _complete_string _int
  inc $i 1

}


Not 100% sure the syntax is correct, sorry.  If I only have 10 interfaces then there isn't going to be a need to issue this loop 200 times for "$_array_vrf_int".  It also wouldn't be great if I went over 200 interfaces.  Is there a way I can limit this loop based on the number of lines that were captured after the split function?


2.    The value of the regexp above is output to the var $_int.  Is there a way I can output the regexp to an array? a'la:-


regexp {([A-Z]+[a-z]+[0-9]+).*} [lindex $_array_vrf_int $i] _complete_string [lindex $_int $i]


Syntax there definitely isn't correct but I guess there might be a way to do this.  Any thoughts?


3.     I've been doing some comparisons on some output to see if an access-list is present on an interface.  I can get a regexp to pull back the name of the access-list on a particular interface but if no access-list exists can I do an if statement on nothing?


set _acl_name 0

regexp {.*ip access-group (.*) in} $_running_int _complete_string _acl_name

if {$_acl_name != 0} {puts "there is a access-list on $_int"} else {puts "there's no acl on $_int :-("}


In the output above I'm setting the value of "$_acl_name" to zero so that I can compare it in the if statement.  This seems like a crap newbie way to do it though.  Is there some kind of wildcard I can put in place of the "0" to match an empty variable. a'la {null}.


4.     Sorry last question.  Can I also reset the variable to {null} using a similar wildcard.  Again I can reset the variable to 0 but it just seems like I don't understand the syntax well enough and there is probably a better method.


5.     I've read several tutorials that cover alot of the basics.  Is there a good reference anyone can suggest so I don't waste any more of your time with these silly questions?  I'm afraid the scripts I've studied on this forum are still way over my head.


Many thanks in advance


Alex

Correct Answer by Joe Clarke about 5 years 3 weeks ago

Don't guess the limit the loop.  That will never end well.  Instead, use a foreach loop to iterate over the number of lines in your output:


set vrf_int [exec "show ip vrf interface"]

foreach line [split $vrf_int "\n"] {
  if { [regexp {([A-Za-z0-9]+).*} $line -> int_name] } {

      puts "Interface name is $int_name"

  }

}


Also, don't use variables that start with '_'.  Those are reserved for Cisco or global use.  Additionally, "exec" is a tclsh only command.  If you are using EEM Tcl, you will need to interact with the CLI library.  You may want to look at our best practices guide at https://supportforums.cisco.com/docs/DOC-12757 for some hints and tricks with using EEM.


You can use -all and -inlined to have regexp return everything in a list.  However, given the loop idea above, you could also use lappend on each pass:


set intlst [regexp -all -inline {([A-Za-z0-9]+).*} $output]


set vrf_int [exec "show ip vrf interface"]

set intlst [list]

foreach line [split $vrf_int "\n"] {
  if { [regexp {([A-Za-z0-9]+).*} $line -> int_name] } {

      lappend intlst $int_name

  }

}




You can use "info exists" or simply check the result of your regexp command to see if a match occurred.  See the example above for the latter.


regexp {.*ip access-group (.*) in} $_running_int _complete_string _acl_name

if {[info exists $_acl_name]} {puts "there is a access-list on $_int"} else {puts "there's no acl on $_int :-("}


You can "reset" a variable by using the "unset" command.


One of the best general Tcl references is the "feather book":


http://www.amazon.com/Practical-Programming-Tcl-4th-Edition/dp/0130385603/ref=sr_1_2?ie=UTF8&qid=1333817448&sr=8-2

  • 1
  • 2
  • 3
  • 4
  • 5
Overall Rating: 5 (1 ratings)
Loading.
Correct Answer
Joe Clarke Sat, 04/07/2012 - 09:51
User Badges:
  • Cisco Employee,
  • Hall of Fame,

    Founding Member

Don't guess the limit the loop.  That will never end well.  Instead, use a foreach loop to iterate over the number of lines in your output:


set vrf_int [exec "show ip vrf interface"]

foreach line [split $vrf_int "\n"] {
  if { [regexp {([A-Za-z0-9]+).*} $line -> int_name] } {

      puts "Interface name is $int_name"

  }

}


Also, don't use variables that start with '_'.  Those are reserved for Cisco or global use.  Additionally, "exec" is a tclsh only command.  If you are using EEM Tcl, you will need to interact with the CLI library.  You may want to look at our best practices guide at https://supportforums.cisco.com/docs/DOC-12757 for some hints and tricks with using EEM.


You can use -all and -inlined to have regexp return everything in a list.  However, given the loop idea above, you could also use lappend on each pass:


set intlst [regexp -all -inline {([A-Za-z0-9]+).*} $output]


set vrf_int [exec "show ip vrf interface"]

set intlst [list]

foreach line [split $vrf_int "\n"] {
  if { [regexp {([A-Za-z0-9]+).*} $line -> int_name] } {

      lappend intlst $int_name

  }

}




You can use "info exists" or simply check the result of your regexp command to see if a match occurred.  See the example above for the latter.


regexp {.*ip access-group (.*) in} $_running_int _complete_string _acl_name

if {[info exists $_acl_name]} {puts "there is a access-list on $_int"} else {puts "there's no acl on $_int :-("}


You can "reset" a variable by using the "unset" command.


One of the best general Tcl references is the "feather book":


http://www.amazon.com/Practical-Programming-Tcl-4th-Edition/dp/0130385603/ref=sr_1_2?ie=UTF8&qid=1333817448&sr=8-2

Alex Steer Tue, 04/10/2012 - 02:07
User Badges:

Hi Joseph,


Thanks again for all your help.  Sorry it's taken a while to respond.  If I'm honest, you'd cooked me with your response and I wanted to give your reply some decent time to digest and gain some level of understanding.  It's been a few years since I was 17, learning pascal and I'm finding the whole tcl scripting particularly hard to get my head around.  After the third level of if/for/foreach with nested split commands etc my brain seems to lose the plot.  Never the less I shall persist.


Using the information you've kindly provided I've since got a nice tclsh only script that will look through a routers vrf interfaces, pick out the ones that have a particular vrf, check each one for an inbound access-list, confirm the access-list meets certain criterial based on a switch/regexp function and finally report on lines that shouldn't be there or are missing all together.  The "unset" command wasn't useful in this scenario unfortunately.  It seems to explicitly delete the variable together and so I can't check if it's empty or not.  I've instead resorted to setting the list variable I was using to 0 for all entries before with the switch function that if matched sets an individual entry to 1 before they are checked at the end to ensure they were all matched. I'm sure it's not the most elegant script in the world and due to the extensive use of the "exec" command, I couldn't actually use it.  Still I'm getting there, abiet very slowly.  The hours that I've spent playing with tcl are certainly racking up now.  I just hope my knowledge is too.


Thanks for the suggestion on the book.  I checked and it is indeed the one I purchased 2 years ago when my interest in eem was first captured.  It's unfortunately very thick and slightly scary!  It also doesn't have any examples of combining switch/regexp functions together, which is a bit annoying considering that's the first thing I've tried to use it for.  Hopefully I'll find it very useful as my understanding gets alittle greater though.


Anyway, thank you again for your extremely helpful responses.  Until the next stupid question!


Kind regards


Alex

Actions

This Discussion