首先,您需要引用EOF刚才的任何部分<<。最自然的方式是<<"EOF",但是<<E"OF"甚至<<""EOF会做。如果没有这个,envsubst将获得${passphrase}已经扩展的字符串。由于envsubst对带有字符串$foo或${foo}子字符串的字符串进行操作,因此事先扩展它们意味着envsubst无关。此外,在您的情况下,shell很可能会扩展${passphrase}为空字符串,因为代码中的变量定义只会影响envsubstshell本身; 除非预先在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设置变量,所以我想这就是你想要的。