I have written a small Expect script to log into a Cisco device; once logged in I want to repeatedly run a command and grep
the output.
#!/usr/bin/expect
send_user "Device name: "
expect_user -re "(.*)\n"
set host $expect_out(1,string)
send_user "Username: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)
stty -echo
send_user -- "Password: "
expect_user -re "(.*)\n"
set pass $expect_out(1,string)
stty echo
send_user "show int "
expect_user -re "(.*)\n"
set intf $expect_out(1,string)
send_user "\n"
spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect ">"
At this point we have logged into the device, I want to execute the command "show int xxx" repeatedly and grep the output for a specific line. grep
isn't in Expect, nor a command like sleep
, so I can loop round executing the show int
command, grepping
out my specific line. How can I mix Expect and Bash like this?
UPDATE: I've pretty much done the script now, I'll post the full script once I get over this last hurdle. A line set bytesnow [exec grep "packets input" \< showint | cut -d \ -f 9]
is throwing the error;
child process exited abnormally
while executing
"exec grep "packets input" < \showint | cut -d \ -f 9"
But it works fine in a test script I wrote. The file ./showint is there, running that command on the command line works fine? I can't work out what's wrong?
UPDATE: More investigation (http://wiki.tcl.tk/8489) has shown me that the grep
exits with status code 1, which means no pattern matches were found, put the command works just fine from the command line? Even with /full/path/to/showint.
END: I fixed my mistake by realising what a fool I had been, answered below. Thanks all for your help :D
This is my first Expect script, its purpose is to give the live (almost, 1 second!) throughput of an interface. The below example gives an interface input speed, because we grep
for the line containing "packets input". Change this to "packets output" to get a live output rate for that interface.
#!/usr/bin/expect
# Long delay for those tricky hostnames
set timeout 60
# Prompt user for device name/IP, username, password,
# and interface to query (gi0/2)
send_user "Device name: "
expect_user -re "(.*)\n"
set host $expect_out(1,string)
send_user "Username: "
expect_user -re "(.*)\n"
set user $expect_out(1,string)
stty -echo
send_user "Password: "
expect_user -re "(.*)\n"
set pass $expect_out(1,string)
send_user "\n"
stty echo
send_user "show int "
expect_user -re "(.*)\n"
set intf $expect_out(1,string)
send_user "\n"
spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect ">"
set byteslast 0
set bytesnow 0
log_user 0
# Enter a continuous loop grabbing the number of bytes that
# have passed through an interface, each second.
# The different in this number each cycle, is essentially
# how much traffic this interface is pushing.
while { true } {
send "show int $intf\r"
expect ">"
set showint [open "showint" "w"]
puts $showint $expect_out(buffer)
close $showint
set bytesnow [exec grep "packets input" \< showint | cut -d \ -f 9]
if { $bytesnow > $byteslast } {
set diff [expr $bytesnow - $byteslast]
set bps [exec expr "$diff" \* 8]
set kbps [exec expr "$bps" \/ 1000]
} elseif { $bytesnow < $byteslast } {
set diff [expr $byteslast - $bytesnow]
set bps [exec expr "$diff" \* 8]
set kbps [exec expr "$bps" \/ 1000]
} elseif { $bytesnow == $byteslast } {
set kbps 0
}
set byteslast $bytesnow
puts "$kbps Kbps\r"
sleep 1
}
As this is my first Expect script, I have no doubt it could be written more efficiently and clearly (that always the case I find), so if anyone has any pointers on this one I'm all ears! :)
My problem with my exec grep
command turned out to be that prior to that, the file I had opened "showint", I hadn't closed, and I was trying to access another file; school boy mistake!