在 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} 变量,但由于该值永远不会改变,所以我可以接受。