Home > Software design >  howto get exit code of script running within expect
howto get exit code of script running within expect

Time:01-14

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

https://www.unix.com/shell-programming-and-scripting/144812-expect-script-obtain-exit-code-remote-command.html

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.

  • Related