How to get the exit code of spawned process in expect shell script?

You get the exit status of the spawned process with the wait command:

expect <<'END'
log_user 0
spawn sh -c {echo hello; exit 42}
expect eof
puts $expect_out(buffer)

lassign [wait] pid spawnid os_error_flag value

if {$os_error_flag == 0} {
    puts "exit status: $value"
} else {
    puts "errno: $value"
}
END
hello

exit status: 42

From the expect man page

wait [args]

delays until a spawned process (or the current process if none is named) terminates.

wait normally returns a list of four integers. The first integer is the pid of the process that was waited upon. The second integer is the corresponding spawn id. The third integer is -1 if an operating system error occurred, or 0 otherwise. If the third integer was 0, the fourth integer is the status returned by the spawned process. If the third integer was -1, the fourth integer is the value of errno set by the operating system. The global variable errorCode is also set.


Change

expect {
"INVALID "  { exit 4 }
timeout     { exit 4 }
}

to

expect {
    "INVALID "  { exit 4 }
    timeout     { exit 4 }
    eof
}

Then add the lassign and if commands.


With the help of glenn, I got solution.. and my final script is::

expect script is

 [Linux Dev:anr ]$ cat testexit.sh
 #!/bin/bash
 export tmp_script_file="/home/anr/tmp_script_temp.sh"
 cp /home/anr/tmp_script $tmp_script_file
 chmod a+x $tmp_script_file
 cat $tmp_script_file
 expect << 'EOF'
 set timeout -1
 spawn  $env(tmp_script_file)
 expect {
 "INVALID "  { exit 4 }
 timeout     { exit 4 }
 eof
 }

 foreach {pid spawnid os_error_flag value} [wait] break

 if {$os_error_flag == 0} {
     puts "exit status: $value"
     exit $value
 } else {
     puts "errno: $value"
     exit $value
 }
 EOF
 echo "spawned process status" $?
 rm -f $tmp_script_file
 echo "done"

Spawned script:

 [Linux Dev:anr ]$ cat tmp_script
 exit 3

Execution of Expect script:

 [Linux Dev:anr ]$ ./testexit.sh
 exit 3
 spawn /home/anr/tmp_script_temp.sh
 exit status: 3
 spawned process status 3
 done

Thanks Glenn once again..


After struggling few days with expanding variable inside the expect heredoc, finally i came across an another approach i thought may be helpful to someone in need. My requirement was to pass command and password to a shell function, execute the command in remote host as part of expect heredoc and get the return exit code.

Example:

function shell_function {
   # Get the command and password as arguments
   # Run command using expect
   # Return the exit code
}

shell_function <cmd> <password>
echo $?

Like everyone else expanding of variable inside the heredoc was a problem, which required exporting the value into an environment variable and use env to get the variable inside heredoc. Since, password was one of the arguments i didn't want to store it as part of an environment variable. So, instead of enclosing heredoc opening with single quotes, the variables of heredoc have been escaped. This allowed the direct usage of arguments passed.

Following is the final script:

#! /bin/bash
# This function runs a command like 'ssh' and provides the password
function run_with_password {
    cmd="$2"
    paswd="$1"
    expect << END
        set timeout 60
        spawn $cmd
        expect {
            "yes/no" { send "yes\r" }
            "*assword*" { send -- $paswd\r }
        }
        expect EOF
        catch wait result
        exit [lindex \$result 3]
END
}

my_password="AnswerIS42Really?"
cmd_to_run="ssh userid@hostname"
cmd_to_run="$cmd_to_run ls .sawfish"
run_with_password $my_password "$cmd_to_run"
echo "Command run code: $?"

In the above code the escaped expect variable is $result. After changing the variable to \$result, the script started working like charm.

My sincere thanks to users who have provided answers to following questions, which served as a stepping stones to reach my solution.

Douglas Leeder: help with expect script, run cat on remote comp and get output of it to the variable

glenn jackman: How to return spawned process exit code in Expect script?