我想使用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 設定變量,所以我想這就是您想要的。