How do I pass a Tcl data structure to Perl with Telnet in between?
I want to telnet into a Cisco router, login and execute a Tcl script that is locally stored in the router's flash. This Tcl script does some proce开发者_运维问答ssing and should return a nested hash (preferred) or a string that represents a XML document.
Is there a way to map a Tcl nested hash to a Perl nested hash, or to return a string that represents a XML document? Does Expect allow me to do any of the above, and how?
Serialise the data to a common exchange format, e.g. a JSON string.
Have the Tcl program emit JSON. Load the JSON from Perl into a hash.
Cisco routers tend to run old versions of Tcl, and to not have a large range of extension packages available. That means that you're quite restricted in what you can do. Luckily, for the job of producing data that can be collected and parsed by Perl, it's actually fairly straight-forward.
Let's use JSON as the interchange format. (Others are possible too.) Daxim's answer tells you how to parse JSON, but that's quite easy because you're running in a context you can control. How to generate JSON data in that crufty old Tcl? The easiest method is with the subst
command — it's been functionally unchanged in Tcl for ages, so you've definitely got it — and a few helper commands. Here's the outline:
proc getFoo {} {
# Some regular Tcl code to get the value
}
proc getFruit {variety} {
# Some regular Tcl code to get the value
}
set someIntValue [expr { 1 + 2 * 3 }] ;# Or whatever...
set jsonTemplate {
{
"foo": [getFoo],
"bar": {
"pears": "[getFruit pears]",
"apples": "[getFruit apples]"
},
"grill": $someIntValue
}
}
puts [subst $jsonTemplate]
OK, caveat time: I've no idea what data you're wanting to receive (“nested hashes” isn't very much to go on). You'll have to add quoting/backslashing where required. Put the procedures before the call to subst
(the order of things matters in Tcl).
This expect script should take the file off the router and leave it in /tmp/xferfile.txt. It will need to be modified with the commands that actually produce the file, since I do not have those, I left placeholders for them in the script. You should be able to use Donal's code for that.
It's been a while since I've played with expect and cisco IOS, so bear with me if this needs some debugging on your end.
#!/usr/bin/expect
set timeout 20
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set prompt1 "Router>"
set prompt2 "Router#"
set prompt3 "bash\$"
set ctrld [expr ("d" & 01xF)]
spawn ssh "$user\@$ip"
expect "Password:"
send "$password\r";
# switch to privileged EXEC level
expect $prompt1 { send "enable" }
# ==================================================
# Modify this line for your needs
# ==================================================
expect $prompt2 { send "command to print Tcl hash" }
# Capture output to variable
set results $expect_out(buffer)
# leave EXEC level
expect $prompt2 { send "exit" }
# Command to log out of router
expect $prompt1 { send "exit" }
# Create text file on localhost
spawn "#!/bin/bash"
expect prompt3 {
send "cat > /tmp/xferfile.txt"
sleep 5
send $results
send $crtld
}
expect prompt3 { send "exit" }
精彩评论