How to parse “show flow monitor-map” output with Tcl

I’m the organizer of a few Meetups, most successful so far is the MySQL Meetup. However, I also started a Tcl Meetup and today, a new member, Maryam (or “Moryam”) joined and sent me a message asking a Tcl question. I decided to answer it on my blog, so others could see the answer.

Her question is: How can I parse the output of “show flow monitor-map” from Cisco IOS into a “keyed list” (or Tcl array)?

Here is what she sent me as sample input and desired sample output:

RP/0/RP1/CPU0:irace-netflow-r1#show flow monitor-map

Flow Monitor Map : fmm1
-------------------------------------------------
Id: 1
RecordMapName: ipv4-raw
ExportMapName: fem1
CacheAgingMode: Normal
CacheMaxEntries: 65535
CacheActiveTout: 1800 seconds
CacheInactiveTout: 15 seconds
CacheUpdateTout: N/A

flowMonitorMap {
    {identifier fmm1}
    {id 1}
    {recordMapName ipv4-raw}
    {exportMapName fem1}
    {cacheAgingMode Normal}
    { cacheMaxEntries 65535}
    {cacheActiveTout 1800}
    { cacheActiveToutUnit Seconds}
    {cacheInactiveTout 15}
    {cacheInactiveToutUnit Seconds}
    {cacheUpdateTout N/A}
}

I’m going to assume that all the network I/O required (probably using something like Expect to automate that task) has already been implemented. For the sake of the code example, I’m putting the output of the “show flow monitor-map” into the variable $input. The result of the parsing will go into a Tcl array, which is an unordered set of key-value pairs. Here is the code:

##
## Set input data.
##

set input {Flow Monitor Map : fmm1
-------------------------------------------------
Id: 1
RecordMapName: ipv4-raw
ExportMapName: fem1
CacheAgingMode: Normal
CacheMaxEntries: 65535
CacheActiveTout: 1800 seconds
CacheInactiveTout: 15 seconds
CacheUpdateTout: N/A}

##
## Initialize output array
##

array unset output
array set output {}

##
## Parse input data, populate output array.
##

foreach line [split $input "\n"] {
    if {[regexp {^([^:]+?)\s*:\s*(\S+)\s*(\S+)?$} $line -> key value units]} {
        if {$key eq "Flow Monitor Map"} {
            set key "identifier"
        }
        set key [string tolower $key 0 0]
        set output($key) $value
        if {[string length $units]} {
            set output(${key}Unit) $units
        }
    }
}

##
## Optional: Display the output.
##

foreach {key value} [array get output] {
    puts [list $key $value]
}

Running this Tcl script produces this output:

cacheActiveToutUnit seconds
cacheActiveTout 1800
cacheMaxEntries 65535
exportMapName fem1
id 1
recordMapName ipv4-raw
cacheUpdateTout N/A
cacheInactiveToutUnit seconds
cacheInactiveTout 15
cacheAgingMode Normal
identifier fmm1

Remember, Tcl arrays are unordered lists, which is why the key-value pairs printed come back in a different order than they were put in. If you need them ordered, you’ll have to specify the ordering, perhaps like this:

foreach key {identifier id recordMapName exportMapName cacheAgingMode
        cacheMaxEntries cacheActiveTout cacheActiveToutUnit
        cacheInactiveTout cacheInactiveToutUnit
        cacheUpdateTout cacheUpdateToutUnit} {
    if {[info exists output($key)]} {
        puts [list $key $output($key)]
    }
}

This will produce the following output:

identifier fmm1
id 1
recordMapName ipv4-raw
exportMapName fem1
cacheAgingMode Normal
cacheMaxEntries 65535
cacheActiveTout 1800
cacheActiveToutUnit seconds
cacheInactiveTout 15
cacheInactiveToutUnit seconds
cacheUpdateTout N/A

Maryam, I hope this helps answer your question, as well as anyone else who’s looking to accomplish a similar task. Have questions or comments about the code? Leave them in the comments section below!

Tags:
,
,
,
,
,
,

Comments

  1. Thanks very much..ur the best. I play a bit with it and get back to you..

  2. Hello Dear,

    {cacheActiveToutUnit Seconds} is the child of the one above it. like it’s its unit. how do I go about implementing the nested ones?
    (my bad, its missing Tab there. )

    The output should have a keyed list structure. I guess I can write a proc that changes array to keyed list. but how do I implement it in a keyed list originally?

    Thanks very much.

  3. Tcl arrays are unordered keyed lists. The output above absolutely is a keyed list structure: each line represents a key-value pair.

    What I think you’re asking for is a hierarchical data structure. Basic Tcl doesn’t directly support hierarchical data structures, however you can store whatever data you want in a Tcl list and it can absolutely be hierarchical in nature. You will just have to write all the necessary code to manipulate your data structure. There may be Tcl packages available that simplify creation and use of higher-level data structures. Google should help you find those.

Speak Your Mind

*