首先,您需要引用EOF
刚才的任何部分<<
。最自然的方式是<<"EOF"
,但是<<E"OF"
甚至<<""EOF
会做。如果没有这个,envsubst
将获得${passphrase}
已经扩展的字符串。由于envsubst
对带有字符串$foo
或${foo}
子字符串的字符串进行操作,因此事先扩展它们意味着envsubst
无关。此外,在您的情况下,shell很可能会扩展${passphrase}
为空字符串,因为代码中的变量定义只会影响envsubst
shell本身; 除非预先在shell中设置具有相同名称的变量(意外?)。
现在我们来看你明确的问题。您可以将结果传递给您希望的任何命令,但仍需要将最终的EOF保持在单独的行中。一种方法是这样的:
passphrase=$(<passphrase) envsubst <<"EOF" | oc create -f -
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
或者您可以在子shell中运行您拥有的代码:
( passphrase=$(<passphrase) envsubst <<"EOF"
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
) | oc create -f -
注意Bash参考手册说
管道中的每个命令都在其自己的子shell中执行
因此,即使在第一个解决方案中,当我们设法构建我们的管道时( )
,它的第一部分(之前|
)仍然在子壳中运行。第二个解决方案使这个子shell明确。在我们使用explicit之后(
,shell等待显式)
。这允许我们在终止后放置一些东西EOF
。
令人惊讶的是,即使使用第一个解决方案,您也可以<<
在单个复合命令中使用多个here document()。这种重定向在管道中没什么意义,但它们可能对&&
和有用||
。
command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF
同样的重新排列,明确的子壳:
( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF
根据情况,您可能更喜欢一种符号而不是另一种符号。
回到你的具体例子。使用子shell,您甚至不需要envsubst
:
( passphrase=$(<passphrase); oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
)
这种方式与前两种方式之间存在一些有趣的差异:
- 这次子壳本身应该扩展
${passphrase}
,因此<<EOF
,不是<<"EOF"
。
- 为此,变量必须为子shell所知,而不仅仅是
oc
; 这意味着… passphrase=$(<passphrase) oc create -f - <<…
(注意缺少分号)是行不通的。
- 从技术上讲,不在子shell中(即没有
( )
)的相同代码也可以工作,但是变量将保留在主shell中。在子shell中运行代码会使变量死掉。在原始代码中,没有为主shell设置变量,所以我想这就是你想要的。