我有一个bash脚本
foo.sh:
#!/bin/bash
echo "start"
. /path/to/bar/bar.ksh
echo "after bar"
getoravariables $1
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 ${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"
执行foo.sh后,我得到:
>./foo.sh validsid
start
b4 getora
after getora
所以我可以说,简单地调用ksh脚本没有问题,因为" b4 getora"和#34;在getora"之后工作。但是执行该功能存在一些问题,因为我没有得到回声" 1"或回声" 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 ()
设置的变量。调试输出表明:
++ 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 "^" " ")
%
我会标记为完整。但是,如果我能够收到更多关于为什么这个解决方法可以解决问题的信息,我将非常感激。
答案 0 :(得分:3)
获取文件会忽略shebang,因此它引用ksh
的事实并不会阻止bash
处理它。
问题出在那一行:
grep -w ${1} ${ORATAB_LOC} | grep -v "#" | sed "s/:/ /g" | read SID ORAHOME ASK
在ksh
下,管道的最后一个组件由主shell运行,而在bash下,它由子shell运行。变量SID,
ORAHOME
和ASK
在bash
下设置后就会丢失。
这是一种解决方法:
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}")
%
如果设置了GLOBPARFIL
,则会正确设置和导出变量,如果未设置GLOBPARFIL
,这可能是一个问题,至少不会挂起脚本。
说明:
运行shell命令管道时,例如command1 | command2 | command3
,bash
解释器正在子shell中运行每个命令。这意味着在其中一个管道命令中完成的任何变量设置都将丢失。在您的脚本中,您有几个command 1 | read variable1 variable2
个成语。这适用于ksh
,它在当前shell中运行read
指令,但不在bash
运行。
便携式解决方法是通过读取行开头的变量来反转命令的顺序,并使用here document
设置读取标准输入。此处文档由任何自定义字符串分隔,常用字符串为%
。这里的文档通常包含标准输入本身作为纯文本。在这里,我们希望此输入是管道中set
指令之前的命令的结果,因此使用command substitution($(command)
)。这是将command
输出放在此处的文档中。
您可能也使用过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}")
答案 1 :(得分:0)
最可能的情况是功能名称&#39; getoravariables&#39;用于在此处未列出的其中一个脚本中定义第二个函数(它不会执行任何可见的操作)。 试着寻找“getoravariables”&#39;在你的所有文件中,也许你找到它。
答案 2 :(得分:0)
我有一个这样的脚本来“强制”执行脚本的bash执行。
#!/bin/sh
#
if [ "$(ps -p "$$" -o comm=)" != "bash" ]; then
exec /usr/local/bin/bash "$0" "$@@"
exit 255
fi
echo blah...
我假设您可以使用类似的东西强制执行ksh。 ps
选项是POSIX,因此它们应该是可移植的。
P.S。如果有更好的方法,请发布它。我并不自豪。