I have a expect script that tries to fetch homepage from of whatismyip site. I need to capture both - site's IP and HTTP return code:
#!/usr/bin/expect -f
set timeout -1
spawn telnet www.whatismyip.com 80
expect "Connected to www.whatismyip.com*"
set output $expect_out(0,string)
regexp {Connected to www\.whatismyip\.com.*?(\d+\.\d+\.\d+\.\d+)} $output match ip
send -- "GET / HTTP/1.0\n"
send -- "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4\n"
send -- "Host: www.whatismyip.com\n"
send -- "\n"
send -- "\n"
set output $expect_out(buffer)
regexp {.*HTTP/1.1 200 OK.*} $output match ret
puts $ip
puts $ret
expect eof
exit 0
There are two issue. Firstly I get the IP truncated by it last character and get error that variable ret not found:
spawn telnet www.whatismyip.com 80
Trying 108.162.200.37...
Connected to www.whatismyip.com (108.162.200.37).
Escape character is '^]'.
108.162.200.3
can't read "ret": no such variable
while executing
"puts $ret"
(file "./t2" line 15)
I tried all way and possibilities but cannot rectify both of them. Please let me know how to rectify this.
First issue: caused by the fact that you have no control of what * is in the $expect_out (imagine the characters are coming slowly and note that "Connected to www.whatismyip.com*" already matches just "Connected to www.whatismyip.com (108.16". Rather use:
set myexpr {Connected to www\.whatismyip\.com.*?(\d+\.\d+\.\d+\.\d+)[^0-9]}; #Note the terminal condition!
expect {
-re $myexpr {
#now $expect_out(0,string) contains the right data to dig...
regexp $myexpr $expect_out(0,string) match ip
}
}
Second issue: note the expression in regexp {.*HTTP/1.1 200 OK.*} $output match ret doesn't contain brackets so $ret will never be filled even if the output contained that string, but I assume the $output was empty anyway, why?
Same as the first issue. Imagine the characters are coming slowly, at the time you do set output $expect_out(buffer) the characters were not received yet (the script itself is usually much faster that data transfer over the network and the buffer is set just after the data were sent, no wait for response). Again, use expect:
expect {
"HTTP/1.1 200 OK" {
#do some stuff here ...
}
}
Related
I'm including simple Expect commands within a Bash script (I know I could be just writing a pure Expect script, but I would like to get it to work from within Bash).
The script is below:
#!/bin/bash
OUTPUT=$(expect -c '
spawn ssh mihail911#blah.org
expect "password:"
send "dog\r"
')
Upon ssh'ing to the above address, it will return something of the form mihail911's password: on the prompt, so I think my expect line is valid.
When I run this my script does not print anything. It does not even show the password: prompt. In general, even if I manually provide an incorrect password, I will receive a Incorrect password-type response prompt. Why is nothing printing and how can I get my script to execute properly?
I have tried debugging by using the -d flag and it seems to show that at least the first expect prompt is being matched properly.
In addition, what values should I expect in the OUTPUT variable? When I echo this variable, it simply prints the first the first command of the expect portion of the script and then mihail911's password:. Is this what it's supposed to be printing?
Use:
#!/bin/bash
OUTPUT=$(expect -c '
# To suppress any other form of output generated by spawned process
log_user 0
spawn ssh dinesh#xxx.xxx.xx.xxx
# To match some common prompts. Update it as per your needs.
# To match literal dollar, it is escaped with backslash
set prompt "#|>|\\$"
expect {
eof {puts "Connection rejected by the host"; exit 0}
timeout {puts "Unable to access the host"; exit 0;}
"password:"
}
send "root\r"
expect {
timeout {puts "Unable to access the host"; exit 0;}
-re $prompt
}
send "date\r"
# Matching only the date cmd output alone
expect {
timeout { puts "Unable to access the host";exit 0}
-re "\n(\[^\r]*)\r"
}
send_user "$expect_out(1,string)\n"
exit 1
')
echo "Expect's return value: $?"; # Printing value returned from 'Expect'
echo "Expect Output: $OUTPUT"
Output:
dinesh#MyPC:~/stackoverflow$ ./Meric
Expect's return value: 1
Expect Output: Wed Sep 2 09:35:14 IST 2015
dinesh#MyPC:~/stackoverflow$
i'm new to expect. trying to write a script for cisco router that takes a list of interfaces as input, iterates over each interface, runs a command, saves output, counts number of lines in output and carries out if/else statements based on count.
I've searched on forums and pieced together the following script based on what other users have advised:
Just pasting code for the loop here for now:
foreach int $interfaces {
match_max 20000
send_user "\n"
send_user "====== Checking $int ======\n"
send_user "\n"
set capture [open output2 w]
expect "#"
send "show policy-map $int out\n"
sleep 1
expect "#"
set output $expect_out(buffer)
puts $capture $output
close $capture
set capture 0
send_user "\n\n---------- $expect_out(buffer) ------------\n\n"
set count 0
set count [exec cat output2 | wc -l]
send_user "\n=========== $int $count ===========\n"
if {$count<3} {
puts "Service policy on ! $ip ! $int ! is not working"
} else {
puts "Service policy on ! $ip ! $int is working"
}
exec echo > output2
}
However, when I run the script the file output2 and expect_out(buffer) always has just one character '#'. So i don't get the required results. For some reason, expect_out(buffer) isn't catching output of the command 'show policy-map $int out' and writing it to the file. I am guessing there's a fundamental coding mistake here in terms of the loop structure.
Help would be much appreciated!
Many thanks.
First off, read this book for expect learning: Exploring Expect
From above book:
All of the matched characters plus the characters that came earlier
but did not match are stored in a variable called expect_out(buffer).
In this case, it is nothing but your pattern which you are expecting and it is #. So what you see it right.
Now, for your requirement, please refer How to access the result of a remote command in Expect. This link has the necessary explanation for you.
Thank you again for your support. I found the issue. There was a '#' preceding the one i was interested in. Changed pattern match and now it works.
I'm executing the below script:
#!/usr/bin/expect -f
#!usr/bin/expect
package require Expect
spawn telnet $serverName $portNum
expect "TradeAggregator>"
send "Clients\r"
expect "Client:"
send "1\r"
expect "1-Client>"
send "Pollers\r"
expect "Client Pollers"
send "2\r"
After executing these lines:
send "Pollers\r"
expect ">"
I am getting below lines in CMD output:
"Client" Pollers
1) "ICTS_ICEFIX_Worker Worker" (ICTS_ICEFIX_Worker Poller): RUNNING
2) "NYMEX UTBAPI Worker" (NYMEX UTBAPI Poller): STOPPED
So here, I want to store the above output in one variable. Then I want to read it line by line and if any lines contains NYMEX word, then I need to fetch the first number (1) in this eg.) and perform some substring method to cut the sting.
How can I get this in tcl script?
Here is a solution:
# After you send "2\r":
expect * ;# Do this to get data in expect_out
foreach line [split $expect_out(buffer) \n] {
if {[string match *NYMEX* $line]} {
set number [scan $line "%d"] ;# Do something with that number
}
}
Discussion
After you send "2\r", we need to capture the output into a variable. Fortunately, Expect provides that with the built-in expect_out variable. All we need is to issue an expect * command
The foreach loop splits the output into lines, and look for NYMEX, if found, we extract the first number and do something useful with it.
I writing a script to read user name, password and host info from a file.
I then parse this info to get the variables. I would then like to add these variables to an expect script that reads all the ip address in my file and performs certain commands on the remote devices that I am trying to log into. The script works when it connects to a known host however What I am seeing is that there is one device that is not up and running and the system promps with the following error.
ssh: connect to host 192.168.3.2 port 22: No route to host
the file
I would like to do 2 things
1. Skip the host and move to the next host
2. log the host that is down to another file so that I can troubleshoot the network issue to that host.
Please see the script below. Please any help is greatly accepted.
#! /usr/bin/expect -f
## Read the file
set fid [open /csv_pars/employee1.csv]
set content [read $fid]
close $fid
## Split into records on newlines
set records [split $content "\n"]
## Iterate over the records
foreach rec $records {
## Split into fields on comma
set fields [split $rec ","]
## Assign fields to variables and print some out...
lassign $fields\ ipaddr username password
puts "$ipaddr"
puts "$username"
puts "$password"
if {$ipaddr == ""} continue
spawn ssh -X "$username#$ipaddr"
sleep 2
expect "password:"
sleep 2
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
You need to expect to see one of two things: the password prompt, or the error message:
spawn ssh -X "$username#$ipaddr"
expect {
-re "password: ?$" {
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
"No route to host" {
set fid [open error.log a]
puts $fid "[clock format [clock seconds]]: No route to host $ipaddr"
close $fid
}
}
I have a bash+expect script which has to connect via ssh to the remote comp (and i can't use ssh keys, need password identification in here), read the file there, find specific line with the "hostname" (like "hostname aaaa1111") and store this hostname into the variable to be used after while. How can i get the value of the "hostname" parameter? I thought that line content will be in $expect_out(buffer) variable (so i can scan it and analyze), but it's not. My script is:
#!/bin/bash
----bash part----
/usr/bin/expect << ENDOFEXPECT
spawn bash -c "ssh root#$IP"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \r"
expect ":~#"
set line $expect_out(buffer)
puts "line = $line, expect_out(buffer) = $expect_out(buffer)"
...more script...
ENDOFEXPECT
When i try to see line variable, i see only this: line = , expect_out(buffer) = (buffer) What is the right way to get the line from the file into the variable?
Or is it possible to open the file on the remote computer with expect, scan the file and get what i need to the variable?
Here http://en.wikipedia.org/wiki/Expect there is an example:
# Send the prebuilt command, and then wait for another shell prompt.
send "$my_command\r"
expect "%"
# Capture the results of the command into a variable. This can be displayed,
set results $expect_out(buffer)
seems that it doesn't work in this case?
You might just want to try and do it all from expect, as expect can control bash.
The following should do what you've described. Not sure if this is exactly what you are trying to do.
#!/bin/sh
# the next line restarts using tclsh \
exec expect "$0" "$#"
spawn bash
send "ssh root#$IP\r"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \n"
expect ":~#"
set extractedOutput $expect_out(buffer)
set list [split $extractedOutput "\n"]
foreach line $list {
set re {(?x)
.*
(*)
-S.*
}
regexp $re $line total extractedValue
if {[info exists extractedValue] && [string length $extractedValue] > 1} {
set exportValue $extractedValue
break # We've got a match!
}
send "exit\r" # disconnect from the ssh session
if {[info exists exportValue] && [string length $exportValue] > 1}{
send "export VARIABLE $exportValue\r"
} else {
send_user "No exportValue was found - exiting\n"
send "exit\r"
close
exit 1
}
# now you can do more things in bash if you like