No echo for expect send command - expect

Got a license agreement which I want to process in expect.
I have the following code
{
/usr/bin/expect << EOD
log_user 0
set timeout 20
spawn -noecho "${filename}" > /dev/null 2>&1
stty -echo;
expect {
"Press Enter to view the End User License Agreement" {
send "\r"
exp_continue
}
"More" {
send " "
exp_continue
}
"Do you accept the End User License Agreement?" {
log_user 0
send "y\r"
log_user 0
}
}
interact
expect eof
EOD
}
Running this I get the following output:
y
It is working fine, but I want to get no output from the expect at all.
My goal is to not echo the send command.
As you can see I have already tried to use the log_user and stty to get this done, but with no luck.
Before using this extra bits in the code, I could see the whole license text on screen. With log_user 0 this is now not showing anymore.
But I still got the y from the last send command, which I'm not able to not echo on screen.
Any advise?
Thanks

With stty -echo itself sufficient to hide the output. But, I am not sure what's wrong with that.
Anyway, try this.
"Do you accept the End User License Agreement?" {
send "y\r"
log_user 0
expect *
}
log_user 1
send \r; # This is optional
interact

Related

expect statement in bash script for error validation of expected output

I have the following expect statement within my bash script:
/usr/bin/expect << EOF
spawn -noecho lucli users add -username user -role admin -email
user#user.com
expect "password:" { send "password\n" }
expect "password:" { send "password\n" }
expect eof
EOF
I want the expect script to validate that the correct output is returned from the CLI command after it passes the passwords and creates the user.
The message I want to validate that gets returned is "added to the system successfully"
I can't figure out how to do that from within the bash script using expect.
Can anyone help?
You could try something like this:
# note the quoted here-doc word
status=$(/usr/bin/expect << 'EOF'
spawn -noecho lucli users add -username user -role admin -email
user#user.com
expect "password:" { send "password\r" }
expect "password:" { send "password\r" }
expect eof
set status [string match "*added to the system successfully*" $expect_out(buffer)]
# $status will be the C-like boolean 0 or 1
exit $status
EOF
)
if [[ $status -eq 1 ]]; then
echo "user added OK"
else
echo "user not added"
fi
ref: https://tcl.tk/man/tcl8.6/TclCmd/string.htm

Expect script: to perform actions after closing ssh

The question is to preserve a variable and to perform actions after closing ssh within expect script inside bash.
This is what I`ve got so far:
echo "Getting package name..."
getPackageName=$(expect -c '
exp_internal 1
log_user 1
global expect_out
# puts "Getting package name..."
spawn ssh -q -o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no -o RSAAuthentication=no -l user 10.20.30.40
sleep 1
expect {
"*sword*" {
send "12341234\r"
}
timeout {
send_user "Error: timeout\n"
exit 1
}
}
expect {
"*user#*>*" {
# getting name of the latest modified file
send "cd /export/home/user/Releases/build/1.3.32.0 && find * -type f -printf '"'"'%T# %p\\n'"'"' | sort -n | tail -1 | cut -f2- -d\" \"\r"
}
timeout {
send_user "Error: timeout\n"
exit 1
}
}
expect {
"BUILD_MAIN*" {
# assigning value to variable
set result_lines [split $expect_out(0,string) \r\n]
set package_filename [lindex $result_lines 0]
puts "package_filename: $package_filename"
}
timeout {
send_user "Error: timeout\n"
exit 1
}
}
expect "*#"
send "exit\r"
# here I need to perform some actions on local machine after ssh logout
expect "Connection*"
send "export LATEST_BUILD=$package_filename\r"
send_user "Message sent to user"
')
So, in the bottom block I am trying to set environment variable (LATEST_BUILD) on the local machine after closing ssh, and also to paste there a value of variable (package_filename) which has been defined earlier during ssh session.
The point here is that I see the last "Message sent to user" in the output, but the previous send "export LATEST_BUILD=12345\r" obviously does not work.
#!/bin/bash
getPackageName=$(expect -c '
# A common prompt matcher
set prompt "%|>|#|\\\$ $"
# To suppress any other form of output generated by spawned process
log_user 0
### Spawning ssh here ###
spawn ssh user#xxx.xx.xxx.xxx
expect "password"
send "welcome!2E\r"
expect -re $prompt
# Your further code
send "exit\r"
expect eof
##### The below segment is not needed ######
##### if your intention is to get only the 'package_filename' value #####
# spawn bash
# expect -re $prompt
# send "export LATEST_BUILD=54.030\r"
# expect -re $prompt
# send "echo \$LATEST_BUILD\r"
# expect -re $prompt
# send "exit\r"
# expect eof
#
##### The End ######
# Enabling logging now ...
log_user 1
# Print only the value which you want to return
puts "$package_filename"
')
echo $getPackageName
eof is used to identify the end-of-file event i.e. closure of connection.
Note : The exported variable LATEST_BUILD only be available for the spawned bash session.
Update :
log_user is used to turn off/on the logging generated by Expect at any time.
log_user 0; # Turn off logging
log_user 1; # Turn on logging
I hope that your only intention is to get the package_filename. So, we don't even need to spawn bash shell. Instead, simply print the value at last, thereby making it to be available to the parent bash script.

Expect conditionals don't seem to be working

Edit: Everything works perfectly without the conditional. Adding in the conditional breaks the script. I've tried conditionals in other simpler scripts and those have worked.
Edit2: Adding the full script as other instances of expect conditionals have worked
I'm trying to modify an autoexpect generated expect script that works when the build succeeds but doesn't handle the build failing.
After significant research, I can't figure out why my expect conditional isn't working
#!/usr/bin/expect -f
set force_conservative 0 ;# 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 $env(SHELL)
match_max 100000
expect "~\$ "
send -- "sudo su\r"
expect "/home/ubuntu# "
send -- "cd ../../opt/application/"
send -- "\r"
expect "/opt/application# "
send -- "./buildwar.sh \r"
expect {
"BUILD SUCCESSFUL\r" {
send -- "su appuser\r"
expect "/opt/application\$ "
send -- "../../home/ubuntu/shutdown.sh \r"
expect "\"outcome\" => \"success\"}"
send -- "exit\r"
expect "/opt/application# "
send -- "./deploywar.sh \r"
expect "BUILD SUCCESSFUL"
send -- "su appuser\r"
expect "/opt/application\$ "
send -- "../../home/ubuntu/startup.sh \r"
expect "Deployed \"application.war\""
send -- "exit\r"
send -- "exit\r"
send -- "exit\r"
exit 0
}
"BUILD FAILED\r" {
exit 1
}
}
You may need to run with expect debugging on (expect -d). You don't actually show what data you are expecting.
It works for me:
$ expect -c '
log_user 0
spawn sh -c {echo "BUILD SUCCESSFUL"}
expect {
"BUILD SUCCESSFUL\r" {
#various and sundry other code to run
exit 123
}
"BUILD FAILED\r" {
exit 56
}
}
'
$ echo $?
123
$ expect -c '
log_user 0
spawn sh -c {echo "BUILD FAILED"}
expect {
"BUILD SUCCESSFUL\r" {
#various and sundry other code to run
exit 123
}
"BUILD FAILED\r" {
exit 56
}
}
'
$ echo $?
56
The issue was that nesting expect statements doesn't seem to work, so instead of the posted code, the following works:
#!/usr/bin/expect -f
set force_conservative 0 ;# 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 $env(SHELL)
match_max 100000
expect "~\$ "
send -- "sudo su\r"
expect "/home/ubuntu# "
send -- "cd ../../opt/application/"
send -- "\r"
expect "/opt/application# "
send -- "./buildwar.sh \r"
expect {
"BUILD SUCCESSFUL\r" {
send -- "su appuser\r"
}
"BUILD FAILED\r" {
exit 1
}
}
expect "/opt/application\$ "
send -- "../../home/ubuntu/shutdown.sh \r"
expect "\"outcome\" => \"success\"}"
send -- "exit\r"
expect "/opt/application# "
send -- "./deploywar.sh \r"
expect "BUILD SUCCESSFUL"
send -- "su appuser\r"
expect "/opt/application\$ "
send -- "../../home/ubuntu/startup.sh \r"
expect "Deployed \"application.war\""
send -- "exit\r"
send -- "exit\r"
send -- "exit\r"
You need to match against \n - though it won't matter if you just omit it.

User input for Expect script

I am new to scripting. How can I write an Expect script to ssh into a device and prompt the user for password? We use a pin + RSA token code as the password so I can't store the password.
#!/usr/bin/expect -f
spawn ssh device1
You will need to use the interact command to type in the password yourself.
The below skeleton should get you on your way:
set prompt "$"
spawn ssh user#host
set timeout 10
expect {
timeout {
puts "Unable to connect"
exit 1
}
#Authenticty Check
"*(yes/no)?" {
send "yes\r"
exp_continue
}
"assword: " {
#Hand control back to user
interact -o "\r" exp_continue
}
"$prompt" {
puts "Cool by the pool"
}
}
I have used this code before to achieve what you wish to achieve. You can take it as a reference point to write your own version of the code.
#!/usr/bin/env expect -f
set passw [lindex $argv 0]
#timeout is a predefined variable in expect which by default is set to 10 sec
set timeout 60
spawn ssh $user#machine
while {1} {
expect {
eof {break}
"The authenticity of host" {send "yes\r"}
"password:" {send "$password\r"}
"*\]" {send "exit\r"}
}
}
wait
#spawn_id is another default variable in expect.
#It is good practice to close spawn_id handle created by spawn command
close $spawn_id
Source: Expect Wiki
The below code will ask the user to enter the password and will use it further in the script where a password will be asked. Just as $pass.
Grabbing password to be used in script further
stty -echo
send_user -- "Enter the password: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set pass $expect_out(1,string)

How to capture SFTP transfer if successful from expect

I was lurking on this site for quite awhile now because I am doing an SFTP in a expect/SH script. SSH keygen is not an option for us since we don't have access to the remote server so we're looking into using expect to provide password arg for SFTP.
Here is the script I am working on, and everything is working here except I want to capture or log to an output file if my transfer ("mput") completed successfully. Any advice on what code to put after the "mput" since if I add an expect_out(buffer) after, it is failing.
#!/bin/ksh
DIRROOT=/apps/gen/e2k/sys/bpp
COPYDIR=$DIRROOT/SENT
FILEHASH=TEST.SOME.FILE.*
if [ ! -f $COPYDIR/$FILEHASH ]; then
echo "No File"
fi
# New FTP credential from GIC
FTPSERV=**********
FTPUSER=**********
FTPPWD=**********
FTPDIR=/to-scs
/usr/local/bin/expect -f - <<EOFEXPECT1
#exp_internal 1
set timeout -1
set log [open "/dir/dir1/dir2/MIKETEST.txt" w]
spawn sftp -oPort=10022 $FTPUSER#$FTPSERV
expect "password:"
send "$FTPPWD\r";
expect "sftp> "
send "lcd $COPYDIR \r";
expect "sftp> "
send "cd /recipient \r";
expect "sftp> "
send "mput TEST.SOME.FILE.*\r";
put $log $expect_out(buffer)
close $log
expect "sftp> "
send "bye\r";
expect eof
EOFEXPECT1
if [ $? -eq 0 ]
then
echo "success"
else
echo "fail"
fi
You should be using puts instead of put and i wouldn't rely on $expect_out(buffer) for error checking. Rather use a nested expect statement to trap for common sftp scenarios/errors.
set timeout -1
send "mput TEST.SOME.FILE.*\r";
expect {
#Check for progress, note does not work with all versions of SFTP
#If a match is found restart expect loop
-re "\[0-9]*%" {
set percent $expect_out(0,string)
puts $logf "File transfer at $percent, continuing..."
exp_continue
}
#Check for common errors, by no means all of them
-re "Couldn't|(.*)disconnect|(.*)stalled" {
puts $logf "Unable to transfer file"
exit 1
}
#OK continue
"sftp>" {
puts $logf "File transfer completed"
}
}
Finally, i don't recommend using timeout of -1 (never) as this will lead to a stuck process sooner or later. Rather make us of a timeout value and trap for the possibility of a timeout to occur in the expect block.
set timeout 60
expect {
#Process timed out
timeout {
puts $logf "File transfer timed out"
}
}

Resources