Reputation: 206
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
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:
[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.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