如何在管道中間使用“此處文檔”?

如何在管道中間使用“此處文檔”?

我想使用heredoc作為模板來產生一些內容:

passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: openshift-passphrase
stringData:
  passphrase: ${passphrase}
EOF

並將其透過管道傳輸到oc create -f -.

如果我在 後面添加管道EOF,則不起作用。

如何透過管道將帶有變數替換的定界文件傳遞給消耗它的東西?

答案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 變得明確。使用explicit後(,shell會等待explicit )。這允許我們在終止之後放置一些東西EOF

<<令人驚訝的是,即使使用第一個解決方案,您也可以在單一複合命令中使用多個此處文件 ( )。這種重定向在管道中沒有什麼意義,但它們對於&&和可能很有用||

command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF

相同的重新排列,具有明確的子 shell:

( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF

根據情況,您可能更喜歡其中一種表示法。

回到你的具體例子。使用子外殼,您甚至不需要envsubst

( passphrase=$(<passphrase); oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: openshift-passphrase
stringData:
  passphrase: ${passphrase}
EOF
)

這種方式與前兩種方式有一些有趣的區別:

  • 這次子 shell 本身應該要擴展${passphrase},因此<<EOF不會<<"EOF"
  • 為此,子 shell 必須知道該變量,而不僅僅是oc;這意味著… passphrase=$(<passphrase) oc create -f - <<…(注意缺少分號)不起作用。
  • 從技術上講,不在子 shell 中(即沒有 )的相同程式碼( )也可以工作,但變數將保留在主 shell 中。在子 shell 中執行程式碼會使變數隨之消失。在您的原始程式碼中,未為主 shell 設定變量,所以我想這就是您想要的。

相關內容