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
CodePudding user response:
You have this
expect -re "(\d )" {
set result $expect_out(1,string)
}
send_user "subscript exit code: $result"
and we can see the output is
-sh-4.2$ subscript exit code: decho $?
0
Because the regular expression "(\d )"
is in double quotes, backslash substitutions will occur, and the pattern becomes (d )
which may not match (do you get a 10 second delay at that point?) -- I suspect this is why $result
is empty.
Backslashes are prevalent in regular expressions. Using braces to quote them is the way to go:
expect -re {\d } {set result $expect_out(0,string)}
Running your expect code with expect -d
(or set exp_internal 1
in the code) emits very verbose expect debug output that is extremely useful to see how your patterns are matching (or not).
Using quoted shell heredocs is (IMO) preferable to using quoted strings to encapsulate code.
Consider
expect -c "
send_user \"my home is \$env(HOME)\\n\"
"
versus
expect << 'END_CODE'
send_user "my home is $env(HOME)\n"
END_CODE
With this technique, you pass shell variable to expect through the environment:
export ora_user=oracle
expect << 'END_EXPECT'
#...
spawn su - $env(ora_user)
END_EXPECT
CodePudding user response:
thanks a lot for your answer Glenn, interesting points mentioned. Regarding the braces versus double quotes - I have changed it like that, but no effect. I have those double quotes escaped by backslash within my code - I think the effect is the same, however, definitely it looks nicer to me and evidently it is safer. I have played with the debug mode of expect - thanks for that, I can see much more info. I have noticed that expect holds much more stuff than I "expected" :-)
==> this is just a snippet:
.\r\n-sh-4.2$ " (spawn_id exp7) match regular expression "\d "? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) "4"
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "\r\n-sh-4"
can't read "expect_out(1,string)": no such element in array
while executing
"set result $expect_out(1,string)"
invoked from within
"expect -re {\d } {set result $expect_out(1,string)}"
As you can see, when I am sending the subscript to be executed I am expecting "" i.e. nothing, just the new prompt line. However, at that point expect is full of stuff, not at all blank - I think, I need to define the prompt exactly:
-sh-4.2$
and then I need to expect it, together with echoed exit code $? and somehow separate exit code integer to get what I want...... I will keep trying.