Wie kann ich ein „Here-Dokument“ in der Mitte einer Pipe verwenden?

Wie kann ich ein „Here-Dokument“ in der Mitte einer Pipe verwenden?

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 EOFdirekt nach in Anführungszeichen setzen <<. Der natürlichste Weg ist <<"EOF", aber <<E"OF"oder sogar <<""EOFreichen aus. Ohne dies envsubsterhalten Sie den String mit ${passphrase}bereits erweitert. Da envsubstmit Strings mit Literalen $foooder ${foo}Teilstrings gearbeitet wird, envsubsthat 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 <<EOFnicht <<"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.

verwandte Informationen