在 makefile 中设置动态 ORACLE_HOME
Setting dynamic ORACLE_HOME in makefile
所以我的组织正在将我们的 Oracle 数据库从 11g 升级到 19c。
以前,在我的 makefile 中,我一直这样设置 ORACLE_HOME:
ORACLE_HOME=/opt/app/oracle/product/11.2.0.4/db_1
然而,Oracle 19c 有一个有趣的特性,每当他们 运行 对其打补丁时,db_1 会逐渐变化,变成 db_2,然后 db_3,随着每个补丁等
所以显然我不能再对 ORACLE_HOME 路径进行硬编码了。
在我的一堆脚本中,我从 ortab 文件中提取当前值,如下所示:
setenv ORACLE_SID DATABASE1
setenv ORACLE_HOME `cat /var/opt/oracle/oratab | sed 's/#.*//g' | grep -w $ORACLE_SID | awk -F: '{print ;}'`
这工作得很好,从 ortab 文件中提取了正确的 ORACLE_HOME 路径。
但是,当我尝试在 makefile 中执行此操作时,如下所示:
ORACLE_SID=DATABASE1
ORACLE_HOME=`cat /var/opt/oracle/oratab | sed 's/#.*//g' | grep -w $ORACLE_SID | awk -F: '{print ;}'`
当我尝试 运行 make:
时出现此错误
$ make
`cat /var/opt/oracle/oratab | sed 's//bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
First RE may not be null
*** Error code 2
make: Fatal error: Command failed for target `file1.o'
很明显该命令没有按我预期的方式工作,但我不确定如何修复它。
如何修复命令以在 makefile 中工作?我是 运行正在使用 Solaris 11。
这不是 GNU make,这只是 Solaris 11 附带的默认 make。
添加更多信息:
我的 ortab 文件如下所示:
$cat /var/opt/oracle/oratab
DATABASE_TEST:/opt/app/oracle/product/11.2.0.4/db_7:Y
DATABASE1:/opt/app/oracle/product/19.0.0.0/db_3:N
DATABASE2:/opt/app/oracle/product/11.2.0.4/db_13:Y
DATABASE3:/opt/app/oracle/product/11.2.0.4/db_1:Y
DATABASE_PROD:/opt/app/oracle/product/11.2.0.4/db_2:Y
所以,我需要做的是,使用 DATABASE1 的 ORACLE_SID,拉出 /opt/app/oracle/product/19.0.0.0/db_3
部分,作为我在 makefile 中的 ORACLE_HOME 目录。
更新:
根据 MadScientist 的以下回答,现在这是我的 makefile:
ORACLE_SID=DATABASE1
#ORACLE_HOME = /opt/app/oracle/product/19.0.0/db_3
ORACLE_HOME = `cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w ${ORACLE_SID} | awk -F: '{print $;}'`
PROC=${ORACLE_HOME}/bin/proc
E_INCLUDE=/path/to/include
print-% : ; @echo $* = $($*)
file1.o: file1.pc
${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
当我硬编码 ORACLE_HOME 时,一切正常。
当我尝试使用动态创建的 ORACLE_HOME 时,出现此错误:
$ make
`cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'`/bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
make: Fatal error: Command failed for target `file1.o'
所以它看起来像是将 ORACLE_HOME 设置为命令本身,而不是命令的结果。
奇怪的是,当我运行打印-ORACLE_HOME时,我得到了预期的结果/opt/app/oracle/product/19.0.0/db_3
嗯,当然是这个:
setenv ORACLE_HOME /opt/app/oracle/product/11.2.0.4/db_1
之前不能在您的 makefile 中,因为这不是有效的 makefile 语法。此外,让我感到惊讶的是,到 2020 年,任何人仍在使用 csh 进行任何操作,尤其是脚本编写。但无论如何。
您遇到的问题是 makefile 不是 shell 脚本并且语法规则不同。当然,makefile 内部包含 shell 个脚本,但仅限于食谱:此处您设置了一个 makefile 变量。因此,将 shell 语句放入变量赋值中可能行不通。
这里有三个问题:首先,makefile 中的变量引用是 $(FOO)
或 ${FOO}
的形式,而不是 $FOO
。其次,#
被视为 makefile 中的注释字符,必须进行转义。最后,如果您确实想要一个实际的 $
而不是变量引用,您必须将其转义,如:$$
。解决这些问题,这应该可行,但请注意,可能有更简单的方法可以做到这一点:
ORACLE_SID = DATABASE1
ORACLE_HOME = `cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w $(ORACLE_SID) | awk -F: '{print $;}'`
你说这之后,这条规则:
PROC=${ORACLE_HOME}/bin/proc
file1.o: file1.pc
${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
给出这个输出:
$ make
`cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'`/bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
make: Fatal error: Command failed for target `file1.o'
该错误消息不是很有帮助,没有任何意义。很遗憾这没有给出更好的信息。
我建议您将规则更改为:
file1.o: file1.pc
echo PROC=\'${PROC}\'; ${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
然后,您应该会在输出中看到如下内容:
$ make
echo PROC=\'`cat /var/opt/oracle/oratab...lots of stuff...
PROC='/...'
make: Fatal error: Command failed for target `file1.o'
您要查看的是输出的第二行 PROC='/...'
并检查该路径 /...
,无论它是什么,以确保它看起来正确。此外,它不应包含任何空格或其他特殊字符等。
如果打印的值看起来有误,您必须修复脚本以使其正确。如果它看起来正确,那么我不知道发生了什么,它一定是你使用的 make 版本的一些特殊之处。
从这里开始的简化示例。此初始版本使用 awk
进行搜索,删除 sed
缺少任何 #
评论
ORACLE_SID := DATABASE1
ORACLE_HOME := $(shell awk -F: "/^$(ORACLE_SID)/ { print $; }" /var/opt/oracle/oratab)
(更新)文档中可能的 Solaris 版本,未经验证:
ORACLE_HOME:sh = awk -F: '/^DATABASE1/ { print $; }' /var/opt/oracle/oratab
我终于让它工作了。
使用@Milag 关于 :sh 命令替换的回答,我能够找到关于 Solaris(不是 GNU)make 的文档:link to documentation
这就是答案:
ORACLE_HOME :sh =cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'
钥匙?如文档所述,不要放置双美元符号:
“与规则中的命令相反,该命令不受宏替换的影响;因此,美元符号 ($) 无需替换为双美元符号 ($$)。”
因此,我还不得不硬编码 DATABASE1
而不是使用 ${ORACLE_SID} 变量,但由于该值永远不会改变,所以我可以接受。
所以我的组织正在将我们的 Oracle 数据库从 11g 升级到 19c。
以前,在我的 makefile 中,我一直这样设置 ORACLE_HOME:
ORACLE_HOME=/opt/app/oracle/product/11.2.0.4/db_1
然而,Oracle 19c 有一个有趣的特性,每当他们 运行 对其打补丁时,db_1 会逐渐变化,变成 db_2,然后 db_3,随着每个补丁等
所以显然我不能再对 ORACLE_HOME 路径进行硬编码了。
在我的一堆脚本中,我从 ortab 文件中提取当前值,如下所示:
setenv ORACLE_SID DATABASE1
setenv ORACLE_HOME `cat /var/opt/oracle/oratab | sed 's/#.*//g' | grep -w $ORACLE_SID | awk -F: '{print ;}'`
这工作得很好,从 ortab 文件中提取了正确的 ORACLE_HOME 路径。
但是,当我尝试在 makefile 中执行此操作时,如下所示:
ORACLE_SID=DATABASE1
ORACLE_HOME=`cat /var/opt/oracle/oratab | sed 's/#.*//g' | grep -w $ORACLE_SID | awk -F: '{print ;}'`
当我尝试 运行 make:
时出现此错误 $ make
`cat /var/opt/oracle/oratab | sed 's//bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
First RE may not be null
*** Error code 2
make: Fatal error: Command failed for target `file1.o'
很明显该命令没有按我预期的方式工作,但我不确定如何修复它。
如何修复命令以在 makefile 中工作?我是 运行正在使用 Solaris 11。
这不是 GNU make,这只是 Solaris 11 附带的默认 make。
添加更多信息:
我的 ortab 文件如下所示:
$cat /var/opt/oracle/oratab
DATABASE_TEST:/opt/app/oracle/product/11.2.0.4/db_7:Y
DATABASE1:/opt/app/oracle/product/19.0.0.0/db_3:N
DATABASE2:/opt/app/oracle/product/11.2.0.4/db_13:Y
DATABASE3:/opt/app/oracle/product/11.2.0.4/db_1:Y
DATABASE_PROD:/opt/app/oracle/product/11.2.0.4/db_2:Y
所以,我需要做的是,使用 DATABASE1 的 ORACLE_SID,拉出 /opt/app/oracle/product/19.0.0.0/db_3
部分,作为我在 makefile 中的 ORACLE_HOME 目录。
更新: 根据 MadScientist 的以下回答,现在这是我的 makefile:
ORACLE_SID=DATABASE1
#ORACLE_HOME = /opt/app/oracle/product/19.0.0/db_3
ORACLE_HOME = `cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w ${ORACLE_SID} | awk -F: '{print $;}'`
PROC=${ORACLE_HOME}/bin/proc
E_INCLUDE=/path/to/include
print-% : ; @echo $* = $($*)
file1.o: file1.pc
${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
当我硬编码 ORACLE_HOME 时,一切正常。
当我尝试使用动态创建的 ORACLE_HOME 时,出现此错误:
$ make
`cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'`/bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
make: Fatal error: Command failed for target `file1.o'
所以它看起来像是将 ORACLE_HOME 设置为命令本身,而不是命令的结果。
奇怪的是,当我运行打印-ORACLE_HOME时,我得到了预期的结果/opt/app/oracle/product/19.0.0/db_3
嗯,当然是这个:
setenv ORACLE_HOME /opt/app/oracle/product/11.2.0.4/db_1
之前不能在您的 makefile 中,因为这不是有效的 makefile 语法。此外,让我感到惊讶的是,到 2020 年,任何人仍在使用 csh 进行任何操作,尤其是脚本编写。但无论如何。
您遇到的问题是 makefile 不是 shell 脚本并且语法规则不同。当然,makefile 内部包含 shell 个脚本,但仅限于食谱:此处您设置了一个 makefile 变量。因此,将 shell 语句放入变量赋值中可能行不通。
这里有三个问题:首先,makefile 中的变量引用是 $(FOO)
或 ${FOO}
的形式,而不是 $FOO
。其次,#
被视为 makefile 中的注释字符,必须进行转义。最后,如果您确实想要一个实际的 $
而不是变量引用,您必须将其转义,如:$$
。解决这些问题,这应该可行,但请注意,可能有更简单的方法可以做到这一点:
ORACLE_SID = DATABASE1
ORACLE_HOME = `cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w $(ORACLE_SID) | awk -F: '{print $;}'`
你说这之后,这条规则:
PROC=${ORACLE_HOME}/bin/proc
file1.o: file1.pc
${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
给出这个输出:
$ make
`cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'`/bin/proc sys_include=/usr/include lines=yes iname=file1.pc oname=file1.c include=/path/to/include
make: Fatal error: Command failed for target `file1.o'
该错误消息不是很有帮助,没有任何意义。很遗憾这没有给出更好的信息。
我建议您将规则更改为:
file1.o: file1.pc
echo PROC=\'${PROC}\'; ${PROC} sys_include=/usr/include lines=yes iname=$*.pc oname=$*.c include=${E_INCLUDE}
然后,您应该会在输出中看到如下内容:
$ make
echo PROC=\'`cat /var/opt/oracle/oratab...lots of stuff...
PROC='/...'
make: Fatal error: Command failed for target `file1.o'
您要查看的是输出的第二行 PROC='/...'
并检查该路径 /...
,无论它是什么,以确保它看起来正确。此外,它不应包含任何空格或其他特殊字符等。
如果打印的值看起来有误,您必须修复脚本以使其正确。如果它看起来正确,那么我不知道发生了什么,它一定是你使用的 make 版本的一些特殊之处。
从这里开始的简化示例。此初始版本使用 awk
进行搜索,删除 sed
缺少任何 #
评论
ORACLE_SID := DATABASE1
ORACLE_HOME := $(shell awk -F: "/^$(ORACLE_SID)/ { print $; }" /var/opt/oracle/oratab)
(更新)文档中可能的 Solaris 版本,未经验证:
ORACLE_HOME:sh = awk -F: '/^DATABASE1/ { print $; }' /var/opt/oracle/oratab
我终于让它工作了。
使用@Milag 关于 :sh 命令替换的回答,我能够找到关于 Solaris(不是 GNU)make 的文档:link to documentation
这就是答案:
ORACLE_HOME :sh =cat /var/opt/oracle/oratab | sed 's/\#.*//g' | grep -w DATABASE1 | awk -F: '{print ;}'
钥匙?如文档所述,不要放置双美元符号:
“与规则中的命令相反,该命令不受宏替换的影响;因此,美元符号 ($) 无需替换为双美元符号 ($$)。”
因此,我还不得不硬编码 DATABASE1
而不是使用 ${ORACLE_SID} 变量,但由于该值永远不会改变,所以我可以接受。