wrapper bash 脚本调用 ksh 脚本但挂在一个函数上

wrapper bash script calls ksh script but hangs on a function

我有一个bash脚本

foo.sh:

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

getoravariables 

bar.ksh(目的只是设置oracle变量):

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

grep -w  ${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"

执行后 foo.sh 我得到:

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

所以我可以说简单地调用 ksh 脚本没有问题,因为 "b4 getora" 和 "after getora" 的 echo 命令有效。但是执行该函数存在一些问题,因为我没有得到我期望的 echo "1" 或 echo "2"。

此外,如果我 运行 foo.sh 作为 ksh 脚本,一切正常。

因此,我可以假设这两种语言在语法上存在某种我没有捕捉到的差异。有人可以帮忙吗?

更新: 我在我的完整 ksh 脚本的顶部添加了 set -x,(我在我的问题中包含的只是一个子集)。我发现脚本挂在我的脚本后面的某个点,即我发布的函数:

++ echo

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

这部分脚本的代码是:

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

所以 $GLOBPARFIL 没有正确设置。它也恰好是一个从 getoravariables () 中提取和设置的变量。调试 tat 的输出证明了这一点:

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

这与下面的@jlliagre 回答一致,声明变量未正确设置。但是,我尝试了解决方法,但结果仍然不理想。

更新 2:

根据提供的信息和逻辑,我找到了真正的来源并创建了一个解决方法:

问题:

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

解决方案:

while read VAR VALUE

do

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

我将标记为完成。但是,如果我能收到更多关于为什么这个解决方法可以解决问题的信息,我将不胜感激。

获取文件会忽略 shebang,因此它引用 ksh 的事实不会阻止 bash 处理它。

问题在于那一行:

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

ksh 下,管道的最后一个组件是主 shell 运行,而在 bash 下,它是子 运行 shell。变量 SID, ORAHOMEASKbash.

下设置后就丢失了

这里有一个解决方法:

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

编辑:

对于第二期,您可以使用:

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

如果设置了 GLOBPARFIL,变量将被正确设置和导出,如果未设置 GLOBPARFIL,这可能是一个问题,至少不会挂起脚本。

解释:

当您 运行 一个 shell 命令管道时,例如command1 | command2 | command3bash 解释器正在 运行 子 shell 中的每个命令。这意味着在其中一个管道命令中完成的任何变量设置都将丢失。在您的脚本中,您有几个 command 1 | read variable1 variable2 成语。这适用于 ksh,其中 运行 当前 shell 中的 read 指令,但不适用于 bash.

一种可移植的解决方法是通过读取行​​首的变量来反转命令的顺序,并使用 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))。这是将 command 输出放在此处的文档中。

您可能还用过process substitution:

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

...

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

最有可能的情况是函数名称 'getoravariables' 用于在此处未列出的脚本之一中定义第二个函数(不执行任何可见的操作)。 尝试在所有文件中 grep 查找 'getoravariables',也许您会找到它。

我有一个这样的脚本可以"force" bash 执行脚本。

#!/bin/sh
#

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

我假设您可以使用类似这样的东西来强制执行 ksh。 ps 选项是 POSIX,因此它们应该是可移植的。

p.s。如果有更好的方法,请post。我不骄傲。