How to capture output of expect script command with expect_out? - expect

#!/usr/bin/expect -f
spawn telnet IP PORT
expect "Escape character is '^]'"
send loadtime
set accum {}
expect {
-regexp {..*} {
append accum "${accum}$expect_out(0,string)"
exp_continue
}
}
puts $accum
The output of loadtime command looks like "Load Time: 2.45"
However, on executing the script, $accum only displays "loadtime" and not "Load Time: 2.45"
How to capture output of loadtime command in variable or local file?

You forgot to press the Enter key: send "loadtime\r"

Related

Run command on cisco switch

I made the below script to login to a switch and execute a command. as soon as i execute the script it logins to switch and exits without running the command.
#!/usr/bin/expect -f
set timeout 3000
spawn bash -c "ssh ananair#10.60.255.100"
expect "*assword:"
send "pass#123\n"
expect "*#"
send "show interfaces status"
I suspect the problem is the missing \n in your final send. If you simply send "string", then expect never hits Enter at the end of the command, And since there's no final expect, it figures its work is done, and exits, probably even before it has a chance to echo the command it sent but never executed.
Consider the following:
#!/usr/bin/expect -f
set timeout 3000
spawn ssh switchhostname # no need to run this inside a shell
expect "ssword:"
send "1ns3cur3\n" # it would be better to use key based auth...
expect "#"
send "term len 0\n" # tell the switch to avoid "More" prompts
expect "#"
send "show interfaces status\n" # note the final "\n"
expect "#" # don't quit until the "show" command finishes
You might also consider getting access to this information via SNMP.
try \r instead of \n
I have my expect script that I use to login to my cisco switches for me. and then I use interact from the expect script that leaves me at the cisco prompt.
I would need to rework it to not show passwords but I can definitely help you out.
I didn't need timeouts in mine.
#!/usr/bin/expect
proc enable {} {
expect "assword:" {
send "<enable password>\r"
expect "#" {
}
}
}
proc login {} {
send "<login password>\r"
expect {
"failed" {
send "<username>\r"
enable
}
">" {
send "en\r"
enable
}
"#" {
}}
}
set user_computer_attached [lindex $argv 0]
set user_computer [split $user_computer_attached "#"]
spawn ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 \
-oGlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null \
-oStrictHostKeyChecking=no $user_computer_attached
expect_after eof {
wait
spawn telnet [lindex $user_computer 1]
expect "name:"
send [lindex $user_computer 0]
send "\r"
expect "assword:" {
login
}
}
expect "assword:" {
login
}
interact

Expect script return value

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$

Remove send command from terminal output while keeping needed output

I am trying to create a script that will log onto a server, run some commands while providing information back to the user.
I can log onto the server fine using the script, my issue is the output I get back. My script is something like this:
#!/bin/bash
/usr/bin/expect << SSHLOGIN
set timeout 600
spawn ssh user#myServer.com
expect {
"Are you sure you want to continue connecting (yes/no)?" {
send "yes\n";exp_continue
}
Password: {
send "$2\n"
}
}
expect {
"# " {
send "echo \"Current Directory is:\" \n"
}
}
expect "# " {
send "pwd \n"
}
expect {
"# " {
send "exit \n"
}
}
wait
SSHLOGIN
& my output is as follows:
spawn ssh user#myServer.com
Password:
You have new mail.
DISPLAY set to user.myServer:0.0
# echo "Current Directory is:"
Current Directory is:
# pwd
/home/user/
The output I am trying to achieve is something like:
spawn ssh user#myServer.com
Password:
You have new mail.
DISPLAY set to user.myServer:0.0
Current Directory is:
/home/user/
I've tried using log_user 0/1, stty etc.. but I can't seem to get it right with those...
Any help would be appreciated.
The problem is that the std output of the spawned process includes both program output and sent commands, the latter just because of echoing from the remote device.
You could manipulate stdout via the log_user command, turning it off while still expecting & capturing, and printing out the output yourself via the "puts" command. Lastly re-enable, if at all needed. The below works because Expect does not read the echoed command until the expect command.
I can't test now so I'll leave you the regexp to match the pwd output (beware of prompts with current paths), but since the point of your question is not the regexp, I figure the following will do for you:
#!/bin/bash
/usr/bin/expect << SSHLOGIN
set timeout 600
spawn ssh user#myServer.com
expect {
"Are you sure you want to continue connecting (yes/no)?" {
send "yes\n";exp_continue
}
Password: {
send "$2\n"
}
}
expect {
"# " {
send "pwd \n"
log_user 0
expect -re "(include_here_between_the_parenthesis_a_regexp_that_matches_your_pwd_output)" {
puts "Current directory is: $expect_out(1,string)"
}
log_user 1
}
expect {
"# " {
send "exit \n"
}
}
wait
SSHLOGIN
As a last comment... why not change the top line to #!/usr/bin/expect and make this an expect script as opposed to a bash one with a here documnet (or whatever that was called)? It's almost pure expect code after all.
Let me know how that goes, and don't forget upvoting or marking the answer if it indeed helped. :-)

Only store/retrieve last line from prompt in expect_out buffer

I wrote the following expect script:
set prompt {$}
set domain $::env(METEOR_DOMAIN)
puts "$domain"
spawn meteor mongo "$domain" --url
set pass "mypassword"
expect {
Password: {
send "$pass\r";
}
}
expect $prompt
puts "The output is '$expect_out(buffer)'."
and the puts command outputs:
The output is ' mypassword
mongodb://client:56099867-e806-3a7a-e5b4-93127e0a3b42#production-db-a1.meteor.io:27017/db_meteor_com'.
which I imagine is what is in the buffer, but I only want the second part (e.g.) the mongo string
How do I make expect only put the last part the buffer or only retrieve the last part in the buffer for storage in an environmental variable?
You can turn off stdout output before the password, and turn it back on afterward. Furthermore, you can parse the output and extract the mongo string. Here is one way to do it:
log_user 0
spawn ...
expect "Password:" {
send "mypassword\r"
}
log_user 1
...
if {[regexp -line {^mongodb:.*$} $expect_out(buffer) url]} {
set url [string trimright $url]
puts "URL is: '$url'"
}
According to the documentation, log_user 0 will turn off stdout, and log_user 1 will turn it back on.

Run cat on remote computer and send output a variable using expect

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

Resources