exit_1
exit_1

Reputation: 1250

wrapper bash script calls ksh script but hangs on a function

I have a bash script

foo.sh:

#!/bin/bash
echo "start"
. /path/to/bar/bar.ksh
echo "after bar"

getoravariables $1

bar.ksh (purpose is to just set oracle variables):

#!/bin/ksh
echo "b4 getora"
getoravariables () {
echo "1"
if [ $# -ne 1 ]
then
echo "2"
        echo "Usage: getoravariables sid"
        exit 1
fi

grep -w ${1} ${ORATAB_LOC} | grep -v "#" | sed "s/:/ /g" | read SID ORAHOME ASK


if [ $? -ne 0 ]
then
        print "Error: Please enter a vaild SID and check the ${orafile} file for correct input"
        return 1
fi

ps -ef|grep pmon|grep ${SID} >> /dev/null

if [ $? -ne 0 ]
then
        print "Error: SID ${SID} does not seem to be started.  "
        return 2
fi

export ORACLE_SID=${SID}
export ORACLE_HOME="${ORAHOME}"
export ORAENV_ASK=NO

. $ORACLE_HOME/bin/oraenv > /dev/null

}
echo "after getora"

After executing foo.sh I get:

>./foo.sh validsid
start
b4 getora
after getora

So I can tell that there is no problem in simply calling the ksh script since the echo commands for "b4 getora" and "after getora" work. But there is some issue with executing the function since I don't get echo "1" or echo "2" which I would expect.

Furthermore, If I run foo.sh as a ksh script, everything works fine.

Therefore, I can assume that there is some sort of difference in syntax between the two languages that i am not catching. Can anyone assist?

UPDATE: I added set -x at the top of my full ksh script, (what I included in my question is just a subset). I found that the script hung at a point later in my script that the function I posted:

++ echo

++ grep -v '#'
++ read VAR VALUE
(hanging here)

Those code for this part of the script is:

echo $GLOBPARFIL
grep -v "#" ${GLOBPARFIL}|while read VAR VALUE
do
        export ${VAR}=${VALUE}
done

So $GLOBPARFIL doesn't get set properly. It also happens to be a variable that gets pulled in and set from getoravariables (). Output from debugging tat demonstrates this:

++ read VAR VALUE
++ export GLOBPARFIL=/home/local/par/global.par
++ GLOBPARFIL=/home/local/par/global.par

This lines up with @jlliagre answer below that declares that the the variables are not getting properly set. However, I tried the workaround with only the same undesirable result.

UPDATE 2:

Following the information and logic provided I was able to find the true source and create a workaround:

PROBLEM:

grep -v "#" ${file_location}| tr "^" " " | while read VAR VALUE

SOLUTION:

while read VAR VALUE

do

        export ${VAR}=${VALUE}
done <<%
$(grep -v "#" ${file_location}| tr "^" " ")
%

I will mark as complete. But if I could receive more information on why exactly this workaround solves the problem I would greatly appreciate it.

Upvotes: 0

Views: 936

Answers (3)

jlliagre
jlliagre

Reputation: 30843

Sourcing a file ignores the shebang so the fact it refers to ksh doesn't prevent bash to process it.

The issue is with that line:

grep -w ${1} ${ORATAB_LOC} | grep -v "#" | sed "s/:/ /g" | read SID ORAHOME ASK

Under ksh, the last component of a pipeline is run by the main shell while under bash, it is run by a subshell. The variables SID, ORAHOME and ASK are then lost just after being set under bash.

Here is a workaround:

read SID ORAHOME ASK <<%
$(grep -w ${1} ${ORATAB_LOC} | grep -v "#" | sed "s/:/ /g")
%

Edit:

For the second issue, you might use:

while read VAR VALUE
do
        export ${VAR}=${VALUE}
done <<%
$(grep -v # "${GLOBPARFIL}")
%

If GLOBPARFIL is set, the variables would be correctly set and exported and if GLOBPARFIL is unset, which is likely an issue, that would at least not hang the script.

Explanation:

When you run a shell command pipeline, e.g. command1 | command2 | command3, the bash interpreter is running every command in a subshell. That means any variable setting done in one of the pipeline commands is lost. In your script, you have several command 1 | read variable1 variable2 idioms. This works with ksh which run the read instruction in the current shell but not with bash.

A portable workaround is to reverse the order of commands by reading the variable at the beginning of the line, and use a here document to set read standard input. A here document is delimited by any custom string and a common one is %. A here document normally contains the standard input itself as plain text. Here we want this input to be the result of the commands that were preceding the set instruction in the pipeline so command substitution ($(command)) is used. This is putting command output in the here document.

You might also have used process substitution:

read SID ORAHOME ASK < <(grep -w ${1} ${ORATAB_LOC} | grep -v "#" | sed "s/:/ /g")

...

while read VAR VALUE
do
        export ${VAR}=${VALUE}
done < <(grep -v "#" "${GLOBPARFIL}")

Upvotes: 3

Erik Bennett
Erik Bennett

Reputation: 1099

I've got a script like this to "force" bash execution of a script.

#!/bin/sh
#

if [ "$(ps -p "$$" -o comm=)" != "bash" ]; then
    exec /usr/local/bin/bash "$0" "$@@"
    exit 255
fi
echo blah...

I assume that you could use something like this to force ksh execution. The ps options are POSIX, so they should be portable-ish.

p.s. If there's a better way to do this, please post it. I'm not proud.

Upvotes: 0

czvtools
czvtools

Reputation: 601

The most likely scenario is that the function name 'getoravariables' was used to define a second function (which doesn't do anything visible) inside one of the scripts that is not listed here. Try to grep for 'getoravariables' in all your files, maybe you find it.

Upvotes: 0

Related Questions