10-15-2013 03:32 AM
Hi All
I am in the process of creating an expect script to capture the output of show commands from various devices and output them as <name of the device>.<command>.txt
However, I am having the following issues:
Could you please review and assist in the issues above?
#!/usr/bin/expect
# Here, we specify all our commands in a list, that we will issue one
# by one at a later time.
set commands {
"show ip route"
"show ip int brief"
"show arp"
}
# Set the date.
set date [timestamp -format %C%y%m%d]
# This variable is for a file called *.txt that has the IP
# of all of the routers you are collecting information from.
set device_list [read [open "routers.txt"]]
# Specify password, as well as what we expect the routers'
# prompt to be.
set pass "*********"
set prompt "#"
# This command tells expect not to echo the output to the console.
exp_log_user 0
# We loop through each device in our list, one by one...
foreach device $device_list {
# Set each device's log file to be the name of the device...
set file_name "$device.txt"
# we initiate the SSH connection
spawn ssh $device -l *********
#If we see a message asking about the device's host key, accept it.
expect -re "Password:" {
exp_send "$pass\r"
}
#exp_send "terminal length 0\n"
foreach cmd $commands {
exp_send "terminal length 0\n"
expect -re $prompt {
exp_log_file -a $file_name.$cmd
exp_send "$cmd\r"
#exp_sleep 2
exp_log_file
}
}
#expect -re $prompt {
#send "term len 0\r"
#}
expect -re $prompt {
exp_send "logout\r"
}
# Turn off logging.
exp_log_file
}
close
Thanks
Pantelis
Solved! Go to Solution.
10-15-2013 08:43 AM
Maybe it's a latency issue. Try adding:
expect -re $prompt
Right before term len 0 is sent.
10-21-2013 04:32 AM
Hi,
I tried your code and it appears like the host #1 is used to connect to the host #2. BUT it only appears like it because:
In reality the connection to host #2 does not originate from the host #1 but from the host you are running the script from.
To clarify, IOS doesn't have a command named "spawn"... so the command would simply fail if you were trying to connect to the host #2 from host #1 using that command.
The code you supplied works for me, all I did was to change the username and password, the code successfully creates files for both the devices I had in the txt-file for the supplied show-commands.
If your experiences differ from mine, I'd next check that you are running the latest versions of expect etc.
10-15-2013 07:28 AM
By the time you start logging, you've already seen the output you want. What about:
send "term len 0\r"
expect -re $prompt
foreach cmd $commands {
exp_log_file -a $file_name.$cmd
send "$cmd\r"
expect -re $prompt
exp_log_file
}
10-15-2013 07:47 AM
Thanks Joseph
It is now logging per file. However it seems that the name of the file and the actual output are not the same. For example, the output "
show arp file has the "show ip int brief" output
show ip int brief has the "show ip route" output
show ip route has a "term len 0" entry
Also again once of the commands was not properly parsed to the router
how ip int brief
^
% Invalid input detected at '^' marker.
10-15-2013 07:56 AM
Try this instead:
match_max [expr 32 * 1024]
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
set output $expect_out(buffer)
set fd [open $filename.$cmd w]
puts $fd $output
close $fd
}
10-15-2013 08:01 AM
exactly the same result
10-15-2013 08:05 AM
I am testing it locally, and it works fine for me. Maybe there's an issue with your prompt pattern. Try changing your prompt to:
set prompt {([#>]) ?$}
10-15-2013 08:14 AM
Did that but still no luck. The device I am quering is a Cisco CISCO2911/K9 with Version 15.1(3)T. No high cpu on the device either
The latest script with the amendement is:
#!/usr/bin/expect
# Here, we specify all our commands in a list, that we will issue one
# by one at a later time.
set commands {
"show ip route"
"show ip int brief"
"show arp"
}
# Set the date.
set date [timestamp -format %C%y%m%d]
# This variable is for a file called routers.txt that has the hostname/IP
# of all of the routers you are collecting information from.tepad
set device_list [read [open "routers.txt"]]
# Specify password, as well as what we expect the routers'
# prompt to be.
set pass "******"
#set prompt "#"
set prompt {([#>]) ?$}
# This command tells expect not to echo the output to the console.
exp_log_user 0
# We loop through each device in our list, one by one...
foreach device $device_list {
# Set each device's log file to be the name of the device...
set file_name "$device"
# we initiate the SSH connection
spawn ssh $device -l *****
#If we see a message asking about the device's host key, accept it.
expect -re "Password:" {
exp_send "$pass\r"
}
# We log our output from each router to its specified file.
#exp_log_file -a $file_name.$date
# Loop through each command that we specified earlier.
send "term len 0\r"
expect -re $prompt
#foreach cmd $commands {
# exp_log_file -a $file_name.$date.$cmd.txt
# send "$cmd\r"
# expect -re $prompt
# exp_sleep 2
# exp_log_file
#}
match_max [expr 32 * 1024]
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
set output $expect_out(buffer)
set fd [open $file_name.$cmd w]
puts $fd $output
close $fd
}
expect -re $prompt {
exp_send "logout\r"
}
# Turn off logging.
exp_log_file
}
one of the output file is:
how ip int brief
^
% Invalid input detected at '^' marker.
10-15-2013 08:25 AM
Here's what I'm using. I have log_user on just to make sure things are going okay.
#!/usr/bin/expect
# Here, we specify all our commands in a list, that we will issue one
# by one at a later time.
set commands [list "show ip route" "show ip int brief" "show arp"]
# Set the date.
set date [timestamp -format %C%y%m%d]
# This variable is for a file called routers.txt that has the hostname/IP
# of all of the routers you are collecting information from.tepad
set device_list [read [open "routers.txt"]]
# Specify the username and password, as well as what we expect the routers'
# prompt to be.
set pass "******"
#set prompt "#"
set prompt {([#>]) ?$}
# This command tells expect not to echo the output to the console.
log_user 1
# We loop through each device in our list, one by one...
foreach device $device_list {
# Set each device's log file to be the name of the device...
set file_name $device
# we initiate the SSH connection
eval spawn ssh $device -l *****
match_max [expr 32 * 1024]
#If we see a message asking about the device's host key, accept it.
interact -o -nobuffer -re "assword: $" return
send "$pass\r"
# We log our output from each router to its specified file.
#exp_log_file -a $file_name.$date
# Loop through each command that we specified earlier.
send "term len 0\r"
expect -re $prompt
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
set output $expect_out(buffer)
set fd [open $file_name.$cmd w]
puts $fd $output
close $fd
}
expect -re $prompt
send "exit\r"
}
10-15-2013 08:34 AM
I am afraid this didn't work for me as well. The output from the putty session to the server is:
[root@*****tmp]# expect test.tcl
spawn ssh
Password:
hostname#show ip route
Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
ia - IS-IS inter area, * - candidate default, U - per-user static route
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
+ - replicated route, % - next hop override
hostname#how ip int brief
^
% Invalid input detected at '^' marker.
hostname#show arp
Protocol Address Age (min) Hardware Addr Type Interface
As a result the output is not saved correctly to the files as mentioned above. for example the "hostname.show ip route" give the "exec motd". Strange that it works fine for you
10-15-2013 08:43 AM
Maybe it's a latency issue. Try adding:
expect -re $prompt
Right before term len 0 is sent.
10-16-2013 01:35 AM
Hi Joseph
Thank you very much. This did the trick. At the moment if I add two or more devices under the router.txt the script uses the previous device to hop to the next. For example if my list has the following devices: 1.1.1.1 and 2.2.2.2 it will try to ssh to 2.2.2.2 from 1.1.1.1 as per below:
1.1.1.1#spawn ssh 2.2.2.2 -l
Is this possible to change this in order to ssh from the server I am running the program from everytime rather that the previous device?
Thanks
Pantelis
10-16-2013 07:05 AM
The spawn looks like it is running from the device, but it is running from the expect host. The log_user output is deceiving because the spawn is not fully closed. In your main foreach loop, add the following at the end:
close
10-17-2013 08:30 AM
Hi Joseph
There is already a "close" file within the foreeach loop.Code below:
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
set output $expect_out(buffer)
set fd [open $file_name.$cmd w]
puts $fd $output
close $fd
}
I've tried to add "close" as per below but I am getting errors
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
#remove zeros from the cmd filename
regsub -all {[ \r\t\n]+} $cmd "" correct_cmd
set output $expect_out(buffer)
set fd [open $file_name-$date-$correct_cmd.txt w]
puts $fd $output
close $fd
}
1.1.1.1#send: spawn id exp7 not open
while executing
"send "$cmd\r""
("foreach" body line 2)
invoked from within
"foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
#remove zeros from the cmd filename
regsub -all {[ \r\t\n]+} ..."
("foreach" body line 20)
invoked from within
"foreach device $device_list {
# Set each device's log file to be the name of the device...
set file_name $device
# we initiate the SSH connection
..."
(file "store_show_commands_switches.tcl" line 21)
10-17-2013 12:40 PM
It looks like you've put the close in the wrong place. Post your current script.
10-18-2013 02:48 AM
Hi Joseph
Late code is:
#!/usr/bin/expect
# Here, we specify all our commands in a list, that we will issue one
# by one at a later time.
set commands [list "sh ip route summary" "show interfaces" "show arp" "sh ip ospf neighbor" "sh ip eigrp neighbor" "sh cdp neighbors"]
# Set the date.
set date [timestamp -format %C%y%m%d]
# This variable is for a file called switches.txt that has the hostname/IP
# of all of the routers you are collecting information from.tepad
set device_list [read [open "switches.txt"]]
# Specify password, as well as what we expect the switch
# prompt to be.
set pass "********"
#set prompt "#"
set prompt {([#>]) ?$}
# This command tells expect not to echo the output to the console.
#exp_log_user 0
#log_user 1
# We loop through each device in our list, one by one...
foreach device $device_list {
# Set each device's log file to be the name of the device...
set file_name $device
# we initiate the SSH connection
eval spawn ssh $device -l ******
match_max [expr 32 * 1024]
#If we see a message asking about the device's host key, accept it.
interact -o -nobuffer -re "assword: $" return
send "$pass\r"
# We log our output from each router to its specified file.
#exp_log_file -a $file_name.$date
# Loop through each command that we specified earlier.
expect -re $prompt
send "term len 0\r"
expect -re $prompt
foreach cmd $commands {
send "$cmd\r"
expect -re $prompt
#remove zeros from the cmd filename
regsub -all {[ \r\t\n]+} $cmd "" correct_cmd
set output $expect_out(buffer)
set fd [open $file_name-$date-$correct_cmd.txt w]
puts $fd $output
close $fd
}
expect -re $prompt
send "exit\r"
}
Thanks
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide