ennox
ennox

Reputation: 206

Expect: ^ does not work in a regular expression describing the command prompt of different Cisco devices

I am currently optimizing an expect script to gather information from different types of Cisco devices and have a rest problem in the area of regular expressions. Many thanks for your kind help upfront.

Background/issue: Cisco Nexus devices use "#" and "# " in command output which impacts the script logic which uses the same characters to recognize the command prompt before sending the next command.

I could solve most issues by using this more specific definition of command prompt:

set prompt {([A-Z,a-z,0-9]+)(%|#|>|\\$)[\\ ]?$}

and then in the script:

expect -re $prompt
send "$cmd\r"

Now I wanted to make this regular expression even more specific, "Start of the line, then the prompt" by adding a carret "^" at the beginning of the regular expression, but this fails and the script runs always into timeout before sending the next cmd.

set prompt {(^[A-Z,a-z,0-9]+)(%|#|>|\\$)[\\ ]?$}

this also fails

set prompt {^([A-Z,a-z,0-9]+)(%|#|>|\\$)[\\ ]?$}

In the logfile I see that the command prompt is prepended by CR (^M, 0x0d).

Even more curious, this works still without running into timeout, so yes there is a CR in front of the Cisco CLI prompt:

set prompt {[\x0d]([A-Z,a-z,0-9]+)(%|#|>|\\$)[\\ ]?$}

But not that when using the "^"

set prompt {^[\x0d]([A-Z,a-z,0-9]+)(%|#|>|\\$)[\\ ]?$}

When using less to browse through the logfile I see this:

^MDevice123# term len 0^M
^MDevice123# show inventory^M

Hexdump shows between end of the line and new line with the prompt:

0d 0d 0a 0d (CR CR LF CR)

Any clue whats going wrong with my goal, to make the regular expression for command prompt more specific by describing the prompt from the beginning up to the end of a line ?

Upvotes: 0

Views: 1027

Answers (1)

glenn jackman
glenn jackman

Reputation: 247062

^ would match the beginning of the buffer, not just the beginning of the line.

Since expect is built on Tcl, you can use Tcl regex syntax to indicate that you want ^ to match the empty string after any newline:

set prompt {(?n)^[[:alnum:]]+[%#>$]\s?$}
# ..........^^^^

Notes:

  • in a bracket expression, using a comma means you want to match a comma as well. Instead of [A-Z,a-z,0-9] you want [A-Za-z0-9] to match letters or number, or use a character class as shown above.
  • I suspect you don't need to capture the bits you parenthesized.

Expanding on the last point, when you do this:

set prompt {([A-Za-z0-9]+)(%|#|>|\\$)[\\ ]?$}
expect -re $prompt

Assume for now that it works as intended. Assume also that your prompt looks like:

myHostname1234>

After the expect, expect will save the captured parts of the regex in the expect_out array:

  • $expect_out(0,string) will contain the text matched by the regex
  • $expect_out(1,string) will contain the letters and numbers captured by "([A-Za-z0-9]+)", in this case "myHostname1234"
  • $expect_out(2,string) will contain the prompt symbol captured by "(%|#|>|\$)", in this case ">"

I suspect you don't use the expect_out variable in your code, so there's no need to get expect to go to the trouble of storing the matched text. I suspect you really don't care what the prompt symbol is.

I know that parentheses are required to group parts of the regex. However, if you don't need to remember the matched text, you can use (?:subpattern) to get the grouping behaviour without the remembering behaviour.

The expect_out array contains other stuff too. Read the expect man page for all the details.

Upvotes: 2

Related Questions