0

I need help getting the firmware version from the output of the Cisco "show version" command

The following is the first line of the show version output (where "12.4(21a)JA1" is the firmware version):

Cisco IOS Software, C1240 Software (C1240-K9W7-M), Version 12.4(21a)JA1, RELEASE
SOFTWARE (fc1)

The below code gives me the error: couldn't compile regular expression pattern: quantifier operand invalid

expect "*#" {send "show version\n"}
expect -re "(?<=Version/s)(.*)(?=/sRELEASE)" {set var1 $expect_out(1,string)}
puts "Firmware Version: $var1"

Thanks for the help

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
atomicluis
  • 127
  • 2
  • 13

2 Answers2

4

Your problem is two-fold. Firstly, Expect doesn't support look-behind constraints (well, not under normal builds). Secondly, your regular expression mixes up what sort of slashes it is using. It's always a good idea to put regular expresions in braces in Tcl and (by extension) Expect. I also recommend using the multi-line version of expect (as shown below) when things get longer, as that's much easier on the eye.

expect "*#" {send "show version\n"}
expect {
    -re {Version\s+(.*),\s+RELEASE} {
        set firmwareVersion $expect_out(1,string)
    }
}
puts "Firmware Version: $firmwareVersion"

The only downside of putting things in braces is that SO formats them wrongly. We can survive such hardship, I think…

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • It's *possible* to rebuild Tcl to use PCRE as its RE engine — though this isn't a supported configuration at the moment, nor even anything that's actually in the main Tcl source tree (I know of a commercial experiment) — and if that's done then Expect *might* work right still. Or it might not; Expect drives the RE engine pretty hard, using a lot of the more obscure features. – Donal Fellows Jul 29 '12 at 23:02
  • +1 I would mention that since he's interacting with a Cisco, he also needs to look for a prompt in the expect... thus my recommendation – Mike Pennington Jul 29 '12 at 23:02
  • btw, your regex needs to be limited with a `?` because `.*` is too greedy and grabs far more than necessary... I would use `(\d.+?),` – Mike Pennington Jul 29 '12 at 23:38
  • @Mike Going to non-greedy doesn't help as much as you might think; Expect applies the pattern as the data comes in so there's no real benefit to saying to keep the match space small. (It would help if there many uses of “`Version`” in the data stream, or if there were two “`RELEASE`” words, but that's not so likely.) Better would be to use `(\S*)` as that is much less likely to match a long piece of text, but it's really not critical as the match space is also bound by the previously-matched prompt. – Donal Fellows Jul 30 '12 at 00:35
  • And I assume he can find the prompt; I don't know the Cisco devices at all (except by reputation). – Donal Fellows Jul 30 '12 at 00:36
  • I have tcl8.5 and expect 5.44.1.15... when I use your regex, it's too greedy and matches several lines of text. If I use the suggestion in my comment above, it matches strictly the IOS version number. I will admit to having the advantage of testing this at will against our infrastructure – Mike Pennington Jul 30 '12 at 00:41
3

Original:

expect "*#" {send "show version\n"}
expect -re "(?<=Version/s)(.*)(?=/sRELEASE)" {set var1 $expect_out(1,string)}
puts "Firmware Version: $var1"

First, as Donal mentioned expect doesn't support look-behind regexps...

Also, I think you'll find it a little challenging to match a string and perform variable substitution while you are interacting. It's quite possible, but it's easier to do this...

Suggested:

expect "*#" {send "show version\n"}
expect "*#" {send "# something else here"}
regexp {Version\s(\d.+?),\sRELEASE\sSOFTWARE} $expect_out(buffer) matched var1
puts "Firmware Version: $var1"
Mike Pennington
  • 41,899
  • 19
  • 136
  • 174