我想要使用 heredoc 作为模板来生成一些内容:
passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
并将其传输至oc create -f -
。
如果我在 后添加管道EOF
,它不起作用。
我怎样才能将带有变量替换的 heredoc 传输到使用它的东西上?
答案1
首先,您需要EOF
在 之后引用 的任何部分<<
。最自然的方式是<<"EOF"
,但<<E"OF"
或 甚至 也<<""EOF
可以。没有这个envsubst
将获得已经扩展的字符串${passphrase}
。由于对具有文字或子字符串envsubst
的字符串进行操作,因此事先扩展它们意味着无关紧要。此外,在您的情况下,shell 很可能会扩展为空字符串,因为代码中的变量定义仅影响,而不影响 shell 本身;除非在 shell 中事先(意外地?)设置了同名变量。$foo
${foo}
envsubst
${passphrase}
envsubst
现在我们来回答你的明确问题。你可以将结果通过管道传输到你想要的任何命令,但你仍然需要将最后的 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 中运行。第二个解决方案使此子 shell 显式化。在我们使用显式 后(
,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 设置,所以我猜这就是您想要的。