如何在管道中间使用“此处文档”?

如何在管道中间使用“此处文档”?

我想要使​​用 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 设置,所以我猜这就是您想要的。

相关内容