for some time I am struggling to get the exit code of a script which I am running from within expect. It is a BASH script and the questionable part looks like this:
expect -c "
log_file $LOG
spawn su - $ora_user
expect ""
send \"source $oraenv_binary\r\"
expect \"ORACLE_SID = \[$ora_user\] \?\"
send \"$SID\r\"
expect \"The Oracle base has been set to /oracle/$SID\"
send \"$execPATHroot/$subscript $args_subscript\r\"
expect ""
send \"echo \$?\r\"
expect -re \"(\\d+)\" {
set result \$expect_out(1,string)
}
send_user \"subscript exit code: \$result\"
log_file
send \"exit\r\"
expect ""
exit [lindex \$result 3]"
sub_rc=$?
Needed to say that this is one of many tries to get the code, however, unsuccessfully. I guess that my problem lies in incorrectly escaped characters or wrong use of brackets.....
When debugging, I am getting the following:
[336] oraenv_binary=/usr/local/bin/oraenv
[338] expect -c '
log_file /var/opt/osit/oracle/log/ora_sbp_patching_root.bash.log
spawn su - oracle
expect
send "source /usr/local/bin/oraenv\r"
expect "ORACLE_SID = \[oracle\] \?"
send "H95\r"
expect "The Oracle base has been set to /oracle/H95"
send "/opt/osit/oracle/bin/ora_sbp_patching_orausr.bash -s H95 -a CHECK -p /imports/e2r2s48ifde0002/CDSAP/DB/oracle/ORA19/SBP/SBP_1915_220419_202205 -h /imports/e2r2s48ifde0002/CDSAP/DB/oracle/ORA19/SBP/SBP_1915_220419_202205/README19P_2205-70004508.HTM -u oracle\r"
expect
send "echo $?\r"
expect -re "(\d+)" {
set result $expect_out(1,string)
}
send_user "subscript exit code: $result"
log_file
send "exit\r"
expect
exit [lindex $result 3]'
.....subscript runs here OK with exit code 0 in this case
-sh-4.2$ subscript exit code: decho $?
0
-sh-4.2$ exit
logout
expected integer but got ""
while executing
"exit [lindex $result 3]"
[357] sub_rc=0
It seems to me that the regex part "(\d+)" is not OK, but perhaps, it is completely a mess... :-) Please help.
I have read and tried these recommendations: Is there a way to expect output without removing it from the buffer in Tcl expect?
https://wiki.tcl-lang.org/page/How+Expect+can+capture+the+exit+code+from+a+remote+command
The final code which works is as follows (much of the credit goes to Glenn for his numerous advices) :
expect -c "
log_file $LOG
spawn su - $ora_user
expect -re {\$ $}
send \"PS1='>'\r\"
expect -re {>$}
send \"source $oraenv_binary\r\"
expect {ORACLE_SID = \[$ora_user\] ? }
send \"$SID\r\"
expect \"The Oracle base has been set to /oracle/$SID\"
send \"$execPATHroot/$subscript $args_subscript\r\"
expect { (subscript) ; exp_continue }
expect -re {>$}
send \"echo \$?\r\"
expect -re {(\d+)\r\n>$} {set result \$expect_out(1,string)}
send_user \"subscript exit code:\$result\n\"
log_file
send \"exit\r\"
expect \"logout\"
exit [lindex \$result 0]"
sub_rc=$?
echo sub_rc:$sub_rc
The first thing after spawn su - $ora_user
is to set the prompt by send \"PS1='>'\r\"
in order to make new lines with prompt less intrusive to expect.
Then after send \"$execPATHroot/$subscript $args_subscript\r\"
I have used the fact, that I have written the subscript to have every line of output populated by (subscript)
keyword. So while the subscript produces the output, the expect keeps going by exp_continue
.
When the $subscript
ends, the prompt >
appears into which the expect sends echo $?
to get exit code of the $subscript
.
This appears on the screen as:
>echo $?
0
>
so the code should expect the integer, return and the new line with prompt - i.e. {(\d+)\r\n>$}
. At that time the expect matches the output and expect_out(1,string)
is correctly populated:
send: sending "echo $?\r" to { exp7 }
Gate keeper glob pattern for '(\d+)\r\n>$' is '*
>'. Activating booster.
expect: does "" (spawn_id exp7) match regular expression "(\d+)\r\n>$"? Gate "*\r\n>"? gate=no
echo $?
0
>
expect: does "echo $?\r\n0\r\n>" (spawn_id exp7) match regular expression "(\d+)\r\n>$"? Gate "*\r\n>"? gate=yes re=yes
expect: set expect_out(0,string) "0\r\n>"
expect: set expect_out(1,string) "0"
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "echo $?\r\n0\r\n>"
Another thing to mention is \n
within send_user \"subscript exit code:\$result\n\"
so to have new line next..
The last change to the code in question is:
exit [lindex \$result 0]"
I have changed the index to 0
as variable result has just one item and index 0
stands for 1st item in the list.