How can I return an error in bash expect? - bash

I have a bash expect script like this, that I use for some operations on Jamf:
spawn firmwarepasswd -setpasswd
expect {
"Enter password:" {
send "$oldpass\r"
exp_continue
}
"Enter new password:" {
send "$newpass\r"
exp_continue
}
"Re-enter new password:" {
send "$newpass\r"
exp_continue
}
}
If the password fails, the script will not exit and jamf will keep trying to execute it. How can I get it to return and exit when the password is wrong?

I don't know Jamf, but I do have a little example for you:
function _cmd {
local cmd="${#?No command?}"
echo -ne "Testing $cmd\t: "
expect 2>&1 <<-EOF
set timeout -1
spawn ${cmd}
expect eof
catch wait result
exit [lindex \$result 3]
EOF
echo $?
}
function _ssh {
local status="${#?No command?}"
read -sp "remote password? " remote_pass
echo -ne "\nTesting ssh\t: "
expect 2>&1 <<-EOF
set timeout -1
spawn ssh $USER#127.0.0.1
expect {
"yes/no" { send "yes\r"; exp_continue }
"*password: " { send "${remote_pass}\r" }
}
expect "*#" { send "exit $status\r" }
expect eof
catch wait result
exit [lindex \$result 3]
EOF
echo $?
}
_cmd false
_cmd true
_ssh 3
exit 0
The last part after expect eof makes sure that the exit status is shared. The _ssh command will exit with status 3.

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 not matching in bash

I have function who is calling expect , but expect is not matching second line, it is matching first match match, I tried all sort of thinks, please help
function login_ssh_user {
logger $FUNCNAME "start"
if [ -z "${LDAPPWD}" ]; then
get_ldap_pwd
fi
echo "\n ${LDAPUSR} \n\n"
echo "\n ${LDAPPWD} \n"
echo "\n ${SOESYS} \n"
export U1="${LDAPUSR}"
export S1="${SOESYS}"
export P1="${LDAPPWD}"
expect << EOF
spawn ssh "$U1#$S1";
expect "password:" { send $P1\r }
expect "$ " { send_user "Login Success ... PASS\n"; send exit\r }
**expect "denied" { send_user "Login Failure ... Fail\n";** send "^C" }
EOF
logger $FUNCNAME "end"
}
Your code indicates you expect to see the password prompt, then you expect to see a shell prompt, then you expect to see Denied. Clearly you will either see the prompt or the denied message:
function login_ssh_user {
#...
export U1="${LDAPUSR}"
export S1="${SOESYS}"
export P1="${LDAPPWD}"
expect << 'EOF'
spawn ssh $env(U1)#$env(S1)
expect "password:" { send $env(P1)\r }
expect {
"$ " { send_user "Login Success ... PASS\n"; send exit\r }
denied" { send_user "Login Failure ... Fail\n"; send \x03 }
}
EOF
logger $FUNCNAME "end"
}
Notes:
I've quoted the EOF in the redirection. That effectively single quotes the whole expect script body
you export your variables, so expect can fetch them out of the env array
both the shell prompt and "denied" are branches in a single expect command. Whichever one expect sees first will "win".
Ctrl+C is \x03

Get the result of remote script in Expect

Im executing the remote script and checking return status of the script but if I do in the following way its returning the status of the password but not the status of the called script.How can I get the return status of the called script. Please help thanks in advance.
#!/usr/bin/expect
proc auto { } {
global argv
set timeout 120
set ip XXXX.XXX.XX.XX
set user name
set password pass
set ssh_opts {-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no}
set script /path-to-script/test.sh
spawn ssh {*}$ssh_opts $user#$ip bash $script {*}$argv
expect "Password:"
send "$password\r"
send "echo $?\r"
expect {
"0\r" { puts "Test passed."; }
timeout { puts "Test failed."; }
}
expect eof
}
auto {*}$argv
You're automating ssh bash remote_script, so you're not going to get a shell prompt where you can echo $? -- ssh will launch your script and then exit.
What you need to do is get the exit status of the spawned process (ssh is supposed to exit with the remote command's exit status). expect's wait command gets you the exit status (among other info)
spawn ssh {*}$ssh_opts $user#$ip bash $script {*}$argv
expect {
"Password:" { send "$password\r"; exp_continue }
timeout { puts "Test failed." }
eof
}
# ssh command is now finished
exp_close
set info [wait]
# [lindex $info 0] is the PID of the ssh process
# [lindex $info 1] is the spawn id
# [lindex $info 2] is the success/failure indicator
if {[lindex $info 2] == 0} {
puts "exit status = [lindex $info 3]"
} else {
puts "error code = [lindex $info 3]"
}

how to check the file on remote host is exsit with shell script

i want check some files on remote host are exsit with shell script,for my local machine and remote host are not be trusted with each other,so i use expect in my script,here are my code
expect << EOF
spawn ssh $src_user#$src_host "test -f $src_pub || echo CheckFalse "
expect {
"yes/no*" {
send "yes\n"
}
"$src_host's password:" {
send "$src_passwd\n"
}
eof { exit }
}
expect CheckFalse { exit 11 }
EOF
if [ $? -ne 11 ];then
echo "file is exsit!"
else
echo "file is not exsit!"
fi
Use ssh with a command (using -c).
ssh otherhost -c 'ls /path/ filename'
And parse the output as you wish
There are a few issues with your script
Using test will only check if the file doesn't exist, rather use ls which gives output in both conditions and is easier to work with in this case.
You should use exp_continue after sending the authenticity check and the password so the expect loop can continue from where it left of from the previous match.
Add checks for $src_pub and 'No such file' in your expect block to trap for both conditions as shown below:
Try below:
spawn ssh $src_user#$src_host "ls $src_pub"
expect {
"yes/no*" {
send "yes\n"
exp_continue
}
-re "(.*)assword:" {
send -- "$src_passwd\n"
}
$src_pub {
exit 0;
}
-re "(.*) No such" {
exit 1;
}
}

How to get expect to set a bash variable

I would like the following expect script to set a variable in the main bash script. In other words I would like to set $SSH_SUCCESS to a pass/fail string. I have tried using $expect_out and $::env(SSH_SUCCESS) but have been unsuccessful. How do I set a bash variable from expect?
expect << EOF
log_user 0
log_file $TEST_LOG
set timeout 5
spawn ssh root#$RADIO_IP
.....
....expect script, echoing the return of an SSH command...
send "echo\$?\n"
expect {
"0" {
send_user "SSH test: PASSED\r"
SSH_SUCCESS="PASSED"
}
"1" {
send_user "SSH test: FAILED\r"
SSH_SUCCESS="FAILED"
}
sleep 1
send_user "\n"
exit
EOF
echo $SSH_SUCCESS
I don't know Expect, but I think it's something like this
SSH_SUCCESS=$(expect <<EOF
...
expect {
"0" {
puts "PASSED"
}
"1" {
puts "FAILED"
}
...
EOF
)
echo $SSH_SUCCESS
There is no way to set a variable.
This is another way to determine the exit status of Expect.
expect << EOF
log_user 0
log_file $TEST_LOG
set timeout 5
spawn ssh root#$RADIO_IP
.....
....expect script, echoing the return of an SSH command...
send "echo\$?\n"
expect -re "\[0-9\]+$"
#set latest command exit status to valiable "exit_code"
set exit_status \$expect_out(0,string)
if { \$exit_status == 0 } {
send_user "SSH test: PASSED\r"
} else {
send_user "SSH test: FAILED\r"
}
sleep 1
send_user "\n"
# exit expect as latest command exit status
exit \$exit_status
EOF
if [ $? -eq 0 ];then
SSH_SUCCESS="PASSED"
else
SSH_SUCCESS="FAILED"
fi
echo ${SSH_SUCCESS}

Resources