Expect send command is not sending - stops sending during script - expect

The problem is the command send "xxxxx" just does not send. The command seem to be completely ignored.
In the script below I am able to log in to the server but no more send commands are transmitted to the server.
At the end there is an example of the output.
The timeout traps were for debugging.
#!/usr/bin/expect -f
## getver_t.sh - Use telnet to get ver from Cisco devices
## Could be asked for login ID or just pasword
set pass {Password1 Pass2}
set index 0
set timeout 5
set host [lindex $argv 0 ]
spawn ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null admin#$host
expect {
"assword:" {
send_user "\n--- sending [lindex $pass $index] ---\n"
send "[lindex $pass $index]\r"
incr index
exp_continue
}
"\>" {
send_user "\n--- I see a prompt ---\n"
send -- "ter len 0\r"
sleep 3
send -- "show inv\r"
sleep 3
send -- "show ver\r"
send_user "\n--- Time to end ---\n"
sleep 3
send -- "exit\r"
sleep 3
exit
}
timeout {
send -- "\r"
set timeout 5
send_user "\n--- TIMED OUT 1 ---\n"
send -- "ter len 0\r"
sleep 3
send -- "show inv\r"
sleep 3
send -- "show ver\r"
sleep 3
send -- "exit\r"
sleep 3
exit
}
}
send_user "\n--- out side land ---\n"
send "\r"
expect {
timeout {
send_user "\n--- TIMED OUT 2 ---\n"
}
}
This is what I see running the script.
$ ./getver_s.sh server1
spawn ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null admin#server1
Warning: Permanently added 'server1,10.1.1.3' (RSA) to the list of known hosts.
Password:
--- sending Password1 ---
Password:
--- sending Pass2 ---
------------------------------------------------------------
Welcome to server1
------------------------------------------------------------
server1>
--- I see a prompt ---
--- Time to end ---
$
I see the "--- I see a prompt ---" and "--- Time to end ---" messages
but the send commands between the send_user commands are not sent to the server.
I have rewritten this script changed the logic and run it off different versions of servers (Debian7 & 8) but the result is always the same.
Why are those send commands not being sent?
Added expect -d output
Login Banner
-------------- CUT ------------------
Password:"
--- sending Password1 ---
send: sending "Password1\r" to { exp7 }
expect: continuing expect
expect: does " " (spawn_id exp7) match glob pattern "assword:"? no
">"? no
expect: does " \r\n" (spawn_id exp7) match glob pattern "assword:"? no
">"? no
Password:
expect: does " \r\nPassword: " (spawn_id exp7) match glob pattern "assword:"? yes
expect: set expect_out(0,string) "assword:"
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) " \r\nPassword:"
--- sending Pass2 ---
send: sending "Pass2\r" to { exp7 }
expect: continuing expect
expect: does " " (spawn_id exp7) match glob pattern "assword:"? no
">"? no
expect: does " \r\n" (spawn_id exp7) match glob pattern "assword:"? no
">"? no
-------------- CUT ------------------
motd
-------------- CUT ------------------
-\r\nServer1>"
--- I see a prompt ---
send: sending "ter len 0\r" to { exp7 }
send: sending "show inv\r" to { exp7 }
send: sending "show ver\r" to { exp7 }
send: sending "exit\r" to { exp7 }
Server1$

Related

Extract EXPECT result to local variable/file

I've been struggling with getting the output from a remote server to a local variable or a local file.
My attempt:
#!/bin/bash
my_pass=!!psw!!
server=10.10.10.10
/usr/bin/expect << ENDOFEXPECT
exp_internal 1 ;# expect internal debugging. remove when not needed
set PROMPT ":~ ?# ?"
set timeout 30
spawn bash -c "ssh root#$server"
expect "assword:"
send "$my_pass\r"
expect -re "$PROMPT"
send -- "df -kh /\r"
expect -re "df\[^\n]+\n.+\n(.+\r\n.+)\r\n"
set command_output $expect_out(1,string)
send_user "$command_output\r"
interact
ENDOFEXPECT
echo "====================="
echo " >> $command_output"
Output:
spawn bash -c ssh root#10.10.10.10
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {154725}
expect: does "" (spawn_id exp4) match glob pattern "assword:"? no
Password:
expect: does "\rPassword: " (spawn_id exp4) match glob pattern "assword:"? yes
expect: set expect_out(0,string) "assword:"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\rPassword:"
send: sending "!!psw!!\r" to { exp4 }
Gate keeper glob pattern for '' is ''. Not usable, disabling the performance booster.
expect: does " " (spawn_id exp4) match regular expression ""? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "df -kh /\r" to { exp4 }
Gate keeper glob pattern for 'df[^
]+
.+
(.+
.+)
' is ''. Not usable, disabling the performance booster.
expect: does " " (spawn_id exp4) match regular expression "df[^\n]+\n.+\n(.+\r\n.+)\r\n"? (No Gate, RE only) gate=yes re=no
expect: does " \r\n" (spawn_id exp4) match regular expression "df[^\n]+\n.+\n(.+\r\n.+)\r\n"? (No Gate, RE only) gate=yes re=no
Last login: Fri Dec 2 23:58:09 2022 from 10.10.10.1
Welcome to server image 2.2
expect: does " \r\nLast login: Fri Dec 2 23:58:09 2022 from 10.10.10.1\r\r\n\r\nWelcome to server image 2.2\r\n\r\n" (spawn_id exp4) match regular expression "df[^\n]+\n.+\n(.+\r\n.+)\r\n"? (No Gate, RE only) gate=yes re=no
REMY_SERVER:~ #
expect: does " \r\nLast login: Fri Dec 2 23:58:09 2022 from 10.10.10.1\r\r\n\r\nWelcome to server image 2.2\r\n\r\n\u001b[?1034h\u001b[1m\u001b[31mREMY_SERVER:~ # \u001b(B\u001b[m" (spawn_id exp4) match regular expression "df[^\n]+\n.+\n(.+\r\n.+)\r\n"? (No Gate, RE only) gate=yes re=no
expect: timed out
interact: received eof from spawn_id exp0
=====================
>>
Expected:
What I ultimately want is to get the output of df -kh into a local variable or even better, append it directly to a local file (on the local machine, not the server on which the command is executed) so that it contains something like:
$ cat ./result.txt
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 20G 18G 1,7G 92% /
Method 1: The proper way is to not use expect and use key pair access :
Step #1
Setup a SSH key pair (google it) and then copy the SSH key to the remote server. To do this I'd recommend using ssh-copy-id.
Step #2
Now with the ability to SSH to a server in place using a key, your above problem turns into this:
$ ssh root#10.10.10.10 "df -kh"
You can get fancy and use here documents (heredocs aka. here-docs) to further enhance this technique.
$ ssh root#10.10.10.10 <<EOF
> df -kh
> EOF
or put the commands in a file and pass them to ssh:
$ ssh root#10.10.10.10 < my.cmds
Method 2: Expect
See the following, expains how to use it properly and a tool to create expect scripts
https://hostadvice.com/how-to/how-to-automate-tasks-in-ssh/
First, your PROMPT regex is not matching. I see the output has some colour codes in it:
expect: does " \r\nLast login: ...REMY_SERVER:~ # \u001b(B\u001b[m" (spawn_id exp4) match regular expression ...
It's good to anchor prompt regexes, and to enclose them in braces. Try
set PROMPT { # \S*$}
Or, assuming the login shell is bash, set a new prompt that's easier to match:
send "$my_pass\r"
expect "Welcome to server"
send -- "PS1='>'\r"
set PROMPT {>$}
expect -re $PROMPT
Next, the relevant code for the question.
send -- "df -kh /\r"
expect -re "df\[^\n]+\n.+\n(.+\r\n.+)\r\n"
set command_output $expect_out(1,string)
send_user "$command_output\r"
I'd adjust your regex a touch:
set cmd "df -kh /"
send -- "$cmd\r"
expect -re "$cmd\r\n(.+)\r\n.*$PROMPT"
Then you're capturing and "echoing" the result correctly
set command_output $expect_out(1,string)
send_user "$command_output\n"
# use a newline here ......^
And to append it to a local file:
set fh [open ./results.txt a]
puts $fh $command_output
close $fh

expect scripts and old network gear outputs ANSI escape characters

Afternoon,
I have googled this all day and even attempted other solutions in python but not had any success.
I have some old-ish network gear that seems to have a weird terminal type when you SSH to them, the one where CTRL+h is backspace!
This is causing problems for my expect script than needs to do 3 things, 1) log in 2) escalate privileges (think cisco enable) 3) save the config
Tried to set the terminal type but not sure that vt100 is correct, i doubt it is. I also added the sleep commands to see if a delay would solve it, no dice.
here is my script so far
#!/usr/bin/expect
set ::env(TERM) vt100
## Get username
send_user "Username: \n"
expect_user -re "(.*)\n" { set user $expect_out(1,string) }
## Get pass
stty -echo
send_user "Password: \n"
expect_user -re "(.*)\n" { set pass $expect_out(1,string) }
stty echo
## Get list of hosts
set f [ open "hosts.txt"]
set hosts [ split [read $f] "\n"]
set hosts [ lreplace $hosts end end ]
close $f
## iterate host
foreach host $hosts {
spawn ssh "$user\#$host"
expect {
"continue connecting" { send "yes\r"; exp_continue }
"assword" { send "$pass\r" }
}
expect "Copyright (c)" {
sleep 1
send "\r"
sleep 1
send "en 14\r"
sleep 1
send "$pass\r"
sleep 1
send "config save\r"
sleep 1
send "exit\r"
}
}
Output from script
deanmoore#laptop% ./zyxel
Username:
dean.moore
Password:
spawn ssh dean.moore#host1
dean.moore#host1's password:
Copyright (c) 1994 - 2013 ZyXEL Communications Corp.
host1> ^[[47;223R%
deanmoore#laptop% 7;223R

Using rsync in expect script with find -ctime give me an error?

I need some help with an expect script and rsync.
When I run rsync in command line like this it works fine:
rsync -avz root#10.33.122.22:'$(find /cluster/storage/nobackup/coremw/var/log/saflog/FaultManagementLog/alarm/ -ctime -1)' /home/imstest/shared/Generate/ReportingT3/tmp/
But when I use my expect script that looks like this I get an error:
#!/usr/bin/expect -f
set host_ip [lindex $argv 0 ]
set user [lindex $argv 1 ]
set password [lindex $argv 2]
set scp_remote_directory [lindex $argv 3 ]
#set scp_remote_filename [lindex $argv 4]
set local_directory [lindex $argv 4]
set force_conservative 1 ;# set to 1 to force conservative mode even if
;# script wasn't run conservatively originally
if {$force_conservative} {
set send_slow {1 .1}
proc send {ignore arg} {
sleep .1
exp_send -s -- $arg
}
}
set timeout -1
#spawn scp $user#$host_ip:$scp_remote_directory/$scp_remote_filename $local_directory/
spawn rsync -azv $user#$host_ip:\'\$(find $scp_remote_directory -ctime -1)\' $local_directory/
#spawn scp $user#$host_ip:$scp_remote_directory/CscfHealthCheckReport_$TagID_$phase* $local_directory/
match_max 100000
expect {
-exact "Are you sure you want to continue connecting (yes/no)? " {
send -- "yes\r"
exp_continue
}
-exact "${user}#${host_ip}'s password: " {
send -- "$password\r"
}
-exact "Password: " {
send -- "$password\r"
}
}
expect eof
The script name is td_general_scp.exp and i run it like this:
./td_general_scp.exp 10.33.122.22 root rootroot /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log /home/imstest/shared/Generate/ReportingT3/tmp
But then i get this error:
spawn rsync -azv root#10.33.122.22:'$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log -ctime -1)' /home/imstest/shared/Generate/ReportingT3/tmp/
Unexpected local arg: /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log
If arg is a remote file/dir, prefix it with a colon (:).
rsync error: syntax or usage error (code 1) at main.c(1362) [Receiver=3.1.0]
expect: spawn id exp6 not open
while executing
"expect eof"
(file "./td_general_scp.exp" line 36)
But the spawn printout looks exactly the same as when i run it in command line?
What am i doing wrong?
Thanks for the help!
I addded the comments from #Shubhangi Pardeshi but now i get this error:
spawn rsync -azv root#10.33.122.22:'$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log -ctime -1 )' /home/imstest/shared/Generate/ReportingT3/tmp/
Password:
receiving incremental file list
rsync: change_dir "/root//$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm" failed: No such file or directory (2)
The scripts looks like this now:
#!/usr/bin/expect -f
set host_ip [lindex $argv 0 ]
set user [lindex $argv 1 ]
set password [lindex $argv 2]
set scp_remote_directory [lindex $argv 3 ]
set local_directory [lindex $argv 4]
set force_conservative 1 ;# set to 1 to force conservative mode even if
;# script wasn't run conservatively originally
if {$force_conservative} {
set send_slow {1 .1}
proc send {ignore arg} {
sleep .1
exp_send -s -- $arg
}
}
set timeout -1
#spawn scp $user#$host_ip:$scp_remote_directory/$scp_remote_filename $local_directory/
spawn rsync -azv $user#$host_ip:\'\$(find\ $scp_remote_directory\ -ctime\ -1\ )\' $local_directory/
#spawn scp $user#$host_ip:$scp_remote_directory/CscfHealthCheckReport_$TagID_$phase* $local_directory/
match_max 100000
expect {
-exact "Are you sure you want to continue connecting (yes/no)? " {
send -- "yes\r"
exp_continue
}
-exact "${user}#${host_ip}'s password: " {
send -- "$password\r"
}
-exact "Password: " {
send -- "$password\r"
}
}
expect eof
Here is the printout i gert when using exp_internal 1 after channging to #Shubhangi Pardeshi suggestion.
spawn rsync -azv root#10.33.122.22:'$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log -ctime -1 )' /home/imstest/shared/Generate/ReportingT3/tmp/
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {115454}
expect: does "" (spawn_id exp6) match exact string "Are you sure you want to continue connecting (yes/no)? "? no
"root#10.33.122.22's password: "? no
"Password: "? no
Password:
expect: does "Password: " (spawn_id exp6) match exact string "Are you sure you want to continue connecting (yes/no)? "? no
"root#10.33.122.22's password: "? no
"Password: "? yes
expect: set expect_out(0,string) "Password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Password: "
send: sending "rootroot\r" to { exp6 }
receiving incremental file list
rsync: change_dir "/root//$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm" failed: No such file or directory (2)
sent 8 bytes received 159 bytes 111.33 bytes/sec
total size is 0 speedup is 0.00
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1655) [Receiver=3.1.0]
rsync: [Receiver] write error: Broken pipe (32)
expect: read eof
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\r\nreceiving incremental file list\r\nrsync: change_dir "/root//$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm" failed: No such file or directory (2)\r\n\r\nsent 8 bytes received 159 bytes 111.33 bytes/sec\r\ntotal size is 0 speedup is 0.00\r\nrsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1655) [Receiver=3.1.0]\r\nrsync: [Receiver] write error: Broken pipe (32)\r\n"
imstest#TCA-Hubba3:~/shared/Generate/ReportingT3/bin$
I missed to chang to ` as the suggestion but now i have the exact row as suggested:
spawn rsync -azv $user#$host_ip:\`\$(find\ $scp_remote_directory\ -ctime\ -1\ )\` $local_directory/
But now I get a permission denied output? I logged in as root it can't be a permission problem. The error output looks like this.
spawn rsync -zv root#10.33.122.22:`$(find /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/Fm*.log -ctime -1 )` /home/imstest/shared/Generate/ReportingT3/tmp/
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {118075}
expect: does "" (spawn_id exp6) match exact string "Are you sure you want to continue connecting (yes/no)? "? no
"root#10.33.122.22's password: "? no
"Password: "? no
Password:
expect: does "Password: " (spawn_id exp6) match exact string "Are you sure you want to continue connecting (yes/no)? "? no
"root#10.33.122.22's password: "? no
"Password: "? yes
expect: set expect_out(0,string) "Password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Password: "
send: sending "rootroot\r" to { exp6 }
bash: /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/FmAlarmLog_20160422_152507.log: Permission denied
sent 8 bytes received 5 bytes 8.67 bytes/sec
total size is 0 speedup is 0.00
expect: read eof
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\r\nbash: /cluster/storage/no-backup/coremw/var/log/saflog/FaultManagementLog/alarm/FmAlarmLog_20160422_152507.log: Permission denied\r\n\r\nsent 8 bytes received 5 bytes 8.67 bytes/sec\r\ntotal size is 0 speedup is 0.00\r\n"
imstest#TCA-Hubba3:~/shared/Generate/ReportingT3/bin$
Below two changes in rsync command in expect script will resolve issue
Escape space in find command- $(find $scp_remote_directory -ctime -1)
replace ' by `
Hence, spawn statement in expect script would look like
spawn rsync -azv $user#$host_ip:\`\$(find\ $scp_remote_directory\ -ctime\ -1\ )\` $local_directory/

Expect: Prompt extending to next line

I am trying to install a software which is a shell script file. I am using expect to do the silent installation.
There is a strange line during the installation of the software where the prompt goes to the next line like this below.
ENTER AN ABSOLUTE PATH, OR PRESS <ENTER> TO ACCEPT THE DEFAULT
:
So I have tried with these 2 options, but it's NOT working!
1. expect " : " { send "/home/tester/IDir\r" }
2. expect "ENTER AN ABSOLUTE PATH, OR PRESS <ENTER> TO ACCEPT THE DEFAULT\
: " { send "/home/tester/IDir\r" }
Expect File
#!/usr/bin/expect -f
#Taking arguments from test.sh file
set File [lindex $argv 0]
set IDir [lindex $argv 1]
spawn sh /home/tester/$File
expect "PRESS <ENTER> TO CONTINUE: " { send "\n" }
exp_internal 1
expect -re "TO ACCEPT THE DEFAULT\r\n.*?:" { send "/home/tester/IDir\r" }
#expect " : " { send "/home/tester/IDir\r" }
expect "IS THIS CORRECT? (Y/N): " { send "Y\n" }
expect "PRESS <ENTER> TO CONTINUE: " { send "\n" }
sleep 2
expect "ENTER THE NUMBER OF THE DESIRED CHOICE: " { send "2\n" }
expect "PRESS <ENTER> TO EXIT THE INSTALLER: " { send "\n" }
sleep 2
expect eof
test.sh file
dir=James/SDD
cd /home/tester
file=`ls | grep xx_yy*_linux_x86-64.bin`
expect script.exp $file $dir
After analyzing the logs, realized that your expect code is getting timed out for most of the cases.
# This timeout is meant for the first expect word 'PRESS <ENTER> TO CONTINUE', so it is proceeding to the next expect word 'TO ACCEPT THE DEFAULT.*?:'
expect: timed out
Gate keeper glob pattern for 'TO ACCEPT THE DEFAULT
.*?: ' is 'TO ACCEPT THE DEFAULT
You need to add the proper timeout handling for the expect statement. Default timeout is 10 seconds. You can change it in a way as follows,
set timeout 120; # Now, timeout value is 2 min
I can see that you have used sleep in some places, in the same way, do that for earlier expect commands as well. (Using timeout would be better in such cases than sleeping.)
#Taking arguments from test.sh file
set File [lindex $argv 0]
set IDir [lindex $argv 1]
# A common handler for timeout.
# Customize it as per your need.
proc my_timeout_handler {} {
puts "Timeout happened :("
exit 1
}
spawn sh /home/tester/$File
set timeout 300; # 5 mins.
expect {
"PRESS <ENTER> TO CONTINUE: " { send "\n" }
timeout {my_timeout_handler}
}
expect {
-re "TO ACCEPT THE DEFAULT\r\n.*?:" { send "/home/tester/IDir\r" }
timeout {my_timeout_handler}
}
expect {
"IS THIS CORRECT? (Y/N): " { send "Y\r" }
timeout {my_timeout_handler}
}
expect {
"PRESS <ENTER> TO CONTINUE: " { send "\r" }
timeout {my_timeout_handler}
}
expect {
"ENTER THE NUMBER OF THE DESIRED CHOICE: " { send "2\r" }
timeout {my_timeout_handler}
}
expect {
"PRESS <ENTER> TO EXIT THE INSTALLER: " { send "\r" }
timeout {my_timeout_handler}
}
expect {
eof {puts "Program completed"}
timeout {my_timeout_handler}
}

The role of puts in expect, script hangs after puts

I'm new to expect and learning from somebody's script. There is a block like this after the ssh command,
expect {
"Password:" {puts stderr "Wrong password."; exit 1}
"Last login:" {puts "Login Successful."}
timeout abort
}
Well, a problem of this in my case is that if this is the first login to the machine, there won't be a "Last login" showing up. So what I did was to add something and thought this might work
expect {
"Password:" {puts stderr "Wrong password."; exit 1}
"Last login:" {puts "Login Successful."}
"# " {puts "Login Successful."}
timeout abort
}
Now it can print the message, however after adding this the script just hang there after login succeeded.
Turning on -d option while running it, looks like it's trying to match "", not sure how does puts results in this? Or what mistake am I making here?
EDIT:
The last few lines of -d output is
expect: does " *********# " (spawn_id exp6) match glob pattern "Password:"? no
"Last login:"? no
"# "? yes
expect: set expect_out(0,string) "# "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) " *********# "
Login Successful too.
expect: does "" (spawn_id exp6) match glob pattern "# "? no
I replaced something with private info with ***. The next line in my script is
expect "# "

Resources