Ich möchte Inhalte generieren und dabei ein Heredoc als Vorlage verwenden:
passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
und leiten Sie es weiter an oc create -f -
.
Wenn ich nach dem ein Pipe-Zeichen einfüge EOF
, funktioniert es nicht.
Wie kann ich ein Heredoc mit Variablensubstitution an etwas weiterleiten, das es verwendet?
Antwort1
Zuerst müssen Sie einen beliebigen Teil von EOF
direkt nach in Anführungszeichen setzen <<
. Der natürlichste Weg ist <<"EOF"
, aber <<E"OF"
oder sogar <<""EOF
reichen aus. Ohne dies envsubst
erhalten Sie den String mit ${passphrase}
bereits erweitert. Da envsubst
mit Strings mit Literalen $foo
oder ${foo}
Teilstrings gearbeitet wird, envsubst
hat das vorherige Erweitern nichts zu tun. Außerdem wird die Shell in Ihrem Fall höchstwahrscheinlich ${passphrase}
zu einem leeren String erweitert, da die Variablendefinition in Ihrem Code nur Auswirkungen hat envsubst
, nicht aber auf die Shell selbst; es sei denn, die Variable mit demselben Namen wurde (aus Versehen?) zuvor in der Shell festgelegt.
Nun kommen wir zu Ihrer expliziten Frage. Sie können das Ergebnis an jeden beliebigen Befehl weiterleiten, aber Sie müssen das endgültige EOF trotzdem in einer separaten Zeile halten. Eine Möglichkeit, dies zu tun, ist wie folgt:
passphrase=$(<passphrase) envsubst <<"EOF" | oc create -f -
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
Oder Sie können den vorhandenen Code in einer Subshell ausführen:
( passphrase=$(<passphrase) envsubst <<"EOF"
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
) | oc create -f -
NotizBash-Referenzhandbuchsagt
Jeder Befehl in einer Pipeline wird in einer eigenen Subshell ausgeführt
also selbst in der ersten Lösung, als wir unsere Pipe ohne konstruieren konnten ( )
, läuft ihr erster Teil (vor |
) trotzdem in einer Subshell. Die zweite Lösung macht diese Subshell explizit. Nachdem wir explicit verwendet haben (
, wartet die Shell auf explicit )
. Dadurch können wir etwas nach dem abschließenden platzieren EOF
.
Überraschenderweise können Sie sogar mit der ersten Lösung mehr als ein here document ( <<
) in einem einzigen zusammengesetzten Befehl verwenden. Solche Umleitungen machen in einer Pipe wenig Sinn, können aber mit &&
und nützlich sein ||
.
command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF
Dasselbe neu angeordnet, mit expliziten Unterschalen:
( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF
Je nach Situation bevorzugen Sie möglicherweise eine Notation gegenüber einer anderen.
Zurück zu Ihrem konkreten Beispiel. Mit einer Subshell brauchen Sie nicht einmal envsubst
:
( passphrase=$(<passphrase); oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
)
Es gibt interessante Unterschiede zwischen diesem Weg und den beiden vorherigen:
- Dieses Mal sollte die Unterschale selbst expandieren
${passphrase}
, also<<EOF
nicht<<"EOF"
. - Damit dies funktioniert, muss die Variable nicht nur der Subshell, sondern auch bekannt sein
oc
; dieses Mittel… passphrase=$(<passphrase) oc create -f - <<…
(beachten Sie das fehlende Semikolon) würde nicht funktionieren. - Technisch gesehen würde derselbe Code
( )
auch ohne Subshell (also ohne ) funktionieren, aber dann würde die Variable in der Hauptshell verbleiben. Wenn Sie den Code in einer Subshell ausführen, wird die Variable mit ihr gelöscht. In Ihrem Originalcode ist die Variable nicht für die Hauptshell festgelegt, daher nehme ich an, dass dies das ist, was Sie wollen.