Executing multiple child scripts - failing

Hi Folks -

Happy Thursday!

I have a need where I have Parent/Control script that calls multiple child scripts. The problem is, after the first child script is executed, it fails to move to the next script. I assume it's due to my script exit?

For instance, in batch to return to the parent process, you exit with the following command:

exit /b <insertexitcodehere>

Is there something simlar in shell?

Here is my code:

source /u01/app/Hyperion_Batch/Scripts/Shell/_env.sh

#::-- Set Script Name --::
_SN=${0##*/}

echo "Script Name: $_SN"
echo "Script Name without EXT: ${_SN%%.sh*}"

#::-- Set Path Variables --::
_MAINPATH=/u01/app/Hyperion_Batch/
_LOGPATH=Logs/
_ERRORPATH=Errors/

#::-- Set Log & Error subdirectory pertaining to specific process --::

_PLOGPATH=LCM_Logs/
_PERRORPATH=LCM_Errors/

#::-- Set Date and Time Variable --::
_DAY=$(date +%d)
_MONTH=$(date +%m)
_YEAR=$(date +%Y)
_DATESTAMP=${_YEAR}${_MONTH}${_DAY}
_HOUR=$(date +%H)
_MINUTE=$(date +%M)
_SECOND=$(date +%S)
_TIME=${_HOUR}${_MINUTE}
_DATETIMESTAMP=${_DATESTAMP}_${_TIME}

#::-- Establish Log and Error File Directories --::
_ARC_LF=${_MAINPATH}${_LOGPATH}${_PLOGPATH}${_YEAR}_${_MONTH}${_DAY}
_ARC_EF=${_MAINPATH}${_ERRORPATH}${_PERRORPATH}${_YEAR}_${_MONTH}${_DAY}
    mkdir -p ${_ARC_LF}
    mkdir -p ${_ARC_EF}

#::-- Prepare File Name Format --::    
_FN=${_TIME}_${_SN%%.sh*}

#::-- Establish standard out and standard error --:: 
_LF=${_ARC_LF}/${_FN}.log
_EF=${_ARC_EF}/${_FN}.err

#::-- Establish LCM Specifics --::

_EPM_SYSTEM_BIN=/u01/app/Oracle/Middleware/user_projects/epmsystem1/bin/
_IMPORTEXPORT_DIR=/u01/app/Oracle/Middleware/user_projects/epmsystem1/import_export/TVeriRep_Automation_Base/
_LCM_DIR=ESB-TVerRep


exec 2>${_EF} > ${_LF}

#:: Begin Script Processing --::
echo ----------------------------------------------------------
echo "Add $LCM_USER & ${LCM_PSWD} to Export XML ..."
echo ----------------------------------------------------------

sed "s/name=\"\" password=\"\"/name=\"${LCM_USER}\" password=\"${LCM_PSWD}\"/" ${_IMPORTEXPORT_DIR}Export.xml > ${_IMPORTEXPORT_DIR}Export1.xml
rm ${_IMPORTEXPORT_DIR}Export.xml
mv ${_IMPORTEXPORT_DIR}Export1.xml ${_IMPORTEXPORT_DIR}Export.xml


echo ---------------------------------------------------------                                                                                                    
echo "Execute ${_LCM_DIR} Life Cycle Management Backup"                                         
echo ---------------------------------------------------------

sh ${_EPM_SYSTEM_BIN}Utility.sh ${_IMPORTEXPORT_DIR}Export.xml

if [ $? -eq 0 ]
then
  echo ---------------------------------------------------------
  echo "${_LCM_DIR} Life Cycle Management Backup Successful"                           
  echo ---------------------------------------------------------
  #::-- If empty, delete YYYY_MMDD error file subdirectory --::
  trap "[ -s ${_EF} ] || rm -f ${_EF} ] && rmdir ${_ARC_EF}" EXIT 0
  
else
  echo ---------------------------------------------------------
  echo "${_LCM_DIR} Life Cycle Management Backup Unsuccessful"                      
  echo ---------------------------------------------------------
  fi
  exit 1
 

Thanks!

You lost me. I can't see your script running several other scripts - just the one

sh ${_EPM_SYSTEM_BIN}Utility.sh ${_IMPORTEXPORT_DIR}Export.xml

So - where is the problem?

Two comments on above script:

  • putting a trap command AFTER all other commands doesn't guarantee it to be executed if need be.
  • that exit 1 will be executed in each and every case independent of the script's result.

Hi Rudi-

Thank you for the note. I'm sorry I wasn't clear.

I have a parent script that calls multiple child scripts and they are setup in the same format as above. The only difference is the directory variable.

My thoughts were my exits were messed up and thus not letting the scrip proceed to the next one.

I was under the impression if return code 0 it would execute the trap command and then exit with a 0 as indicated by EXIT 0 at the end of the trap line.

Thats wrong? Can you explain? Thank you!

trap sets a trap for the entire script and is valid ONLY after it was set - so set it pretty soon. And, please adhere not only to its syntax but to its logics as well - EXIT 0 specifies the sigspec twice, c.f. man bash .
As already said, your script will exit 1 unconditionally - no further scripts will be executed.

Interesting okay. So how would you change the exit portion of the script to exit with 0 unless an error?

looks like I've set all my scripts up this way, darnit.

Put the exit 1 into the else branch. Note though, that no other scripts may be executed if one fails, then.

+1 @RudiC!

When i write complex processing scripts where all sorts of things could go wrong i usually do it this way:

First, a list of commands that have to be executed (in case everything works perfectly). Let us say the list is:

cmd1 -a -b
cmd2 /bla/foo/bar
cmd3

Then i write the script like this:

if ! cmd1 -a -b ; then
     echo "Error executing cmd1 -a -b" >2&
     exit 3
fi

if ! cmd2 /bla/foo/bar ; then
     echo "Error executing cmd2 /bla/foo/bar" >2&
     exit 2
fi

if ! cmd3 ; then
     echo "Error executing cmd3"  >2&
     exit 1
fi

exit 0

Notice that the script will exit with a different error code depending on which command the script fails. Also notice that convention in UNIX is that a RC of 0 means "success" and everything else means varying reasons of failure. This is why the fi-construct (usually) works: a command succeeding in what it is suppsed to do will return 0 and therefore if ! cmd... will evaluate to false whereas a command not succeeding will return non-0 and if ! cmd... will return true triggering the then..fi .

I hope this helps.

bakunin

@Rudi -

Thank you so much. I have to say, that was a complete oversight on my part! I copied that exit portion in wrong.

It should be:

exit 1
fi

As far as the trap command, I've put earlier in the script. Is that correct?

@bakunin -

Thank you for that explanation. If I followed it correctly, my script should look like the following:

source /u01/app/Hyperion_Batch/Scripts/Shell/_env.sh

#::-- Set Script Name --::
_SN=${0##*/}

echo "Script Name: $_SN"
echo "Script Name without EXT: ${_SN%%.sh*}"

#::-- Set Path Variables --::
_MAINPATH=/u01/app/Hyperion_Batch/
_LOGPATH=Logs/
_ERRORPATH=Errors/

#::-- Set Log & Error subdirectory pertaining to specific process --::

_PLOGPATH=LCM_Logs/
_PERRORPATH=LCM_Errors/

#::-- Set Date and Time Variable --::
_DAY=$(date +%d)
_MONTH=$(date +%m)
_YEAR=$(date +%Y)
_DATESTAMP=${_YEAR}${_MONTH}${_DAY}
_HOUR=$(date +%H)
_MINUTE=$(date +%M)
_SECOND=$(date +%S)
_TIME=${_HOUR}${_MINUTE}
_DATETIMESTAMP=${_DATESTAMP}_${_TIME}

#::-- Establish Log and Error File Directories --::
_ARC_LF=${_MAINPATH}${_LOGPATH}${_PLOGPATH}${_YEAR}_${_MONTH}${_DAY}
_ARC_EF=${_MAINPATH}${_ERRORPATH}${_PERRORPATH}${_YEAR}_${_MONTH}${_DAY}
    mkdir -p ${_ARC_LF}
    mkdir -p ${_ARC_EF}

#::-- Prepare File Name Format --::    
_FN=${_TIME}_${_SN%%.sh*}

#::-- Establish standard out and standard error --:: 
_LF=${_ARC_LF}/${_FN}.log
_EF=${_ARC_EF}/${_FN}.err

#::-- Establish LCM Specifics --::

_EPM_SYSTEM_BIN=/u01/app/Oracle/Middleware/user_projects/epmsystem1/bin/
_IMPORTEXPORT_DIR=/u01/app/Oracle/Middleware/user_projects/epmsystem1/import_export/TVeriRep_Automation_Base/
_LCM_DIR=ESB-TVerRep


exec 2>${_EF} > ${_LF}
trap "[ -s ${_EF} ] || rm -f ${_EF} ] && rmdir ${_ARC_EF}"

#:: Begin Login Process --::
echo ----------------------------------------------------------
echo "Execute all command lines"
echo ----------------------------------------------------------

sed "s/name=\"\" password=\"\"/name=\"${LCM_USER}\" password=\"${LCM_PSWD}\"/" ${_IMPORTEXPORT_DIR}Export.xml > ${_IMPORTEXPORT_DIR}Export1.xml
rm ${_IMPORTEXPORT_DIR}Export.xml
mv ${_IMPORTEXPORT_DIR}Export1.xml ${_IMPORTEXPORT_DIR}Export.xml
sh ${_EPM_SYSTEM_BIN}Utility.sh ${_IMPORTEXPORT_DIR}Export.xml

#:: Begin Error Check --::
echo ---------------------------------------------------------                                                                                                
echo "Check for command line errors"                                         
echo ---------------------------------------------------------

if ! "s/name=\"\" password=\"\"/name=\"${LCM_USER}\" password=\"${LCM_PSWD}\"/" ${_IMPORTEXPORT_DIR}Export.xml > ${_IMPORTEXPORT_DIR}Export1.xml ; then
     echo "Error adding ${LCM_USER} and ${LCM_PSWD} to Export.xml" >2&
     exit 4
fi

if ! rm ${_IMPORTEXPORT_DIR}Export.xml > ${_IMPORTEXPORT_DIR}Export1.xml ; then
     echo "Error removing Export.xml" >2&
     exit 3
fi

if ! mv ${_IMPORTEXPORT_DIR}Export1.xml ${_IMPORTEXPORT_DIR}Export.xml ; then
     echo "Error renaming Export1.xml to Export.xml" >2&
     exit 2
fi

if ! sh ${_EPM_SYSTEM_BIN}Utility.sh ${_IMPORTEXPORT_DIR}Export.xml ; then
     echo "Error executing LCM Backup for ${_LCM_DIR} " >2&
     exit 1
fi

exit 0

Is that correct?

Thank you, both!

As long as it's early enough to catch all the events it is intended for, yes. You are missing the trap events/signals in your new script, though.

Hi Rudi -

I guess im confused. Where would the trap command go then? After the command lines but before the exit portions?

Also, with the new script format, what happens when I'd only want the next command to execute only if the previous one is successful? With the new format, wont all commands execute regardless of return code?

Thanks!

Why not put the trap command in the script's second line right after the "shebang"? You need to get your head around it - it is not executing anything but setting a pointer to a command to be executed when the signals (in sigspec) occur any time during script execution.
And no - failing commands will make the script exit with the respective exit code.

More or less. In fact there are some syntactical errors like:

[...snip...]
if ! "s/name=\"\" password=\"\"/name=\"${LCM_USER}\" [...snip]

Where perhaps the initial command sed is missing, but i suppose that comes from copying. Otherwise you got it.

bakunin

Thank you all so much!