Wie kann ich hier ein Dokument in der Mitte einer Pipe verwenden?

733
simbo1905

Ich möchte einige Inhalte generieren:

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

und pfeife es an oc create -f -.

Wenn ich eine Pfeife nach dem füge EOF, funktioniert es nicht.

Wie kann man den mehrzeiligen Befehl an etwas übergeben, das ihn verbraucht?

0
Funktioniert nicht nach dem ersten EOF? Paulo vor 5 Jahren 0
@paulo entweder schließt `EOF |` die Mehrfachzeile nicht oder `EOF`, dann beendet Newline die Arbeit und ein nachfolgendes | steht am Anfang eines neuen Befehls simbo1905 vor 5 Jahren 0

1 Antwort auf die Frage

1
Kamil Maciorowski

Zuerst müssen Sie einen beliebigen Teil EOFkurz danach zitieren <<. Der natürlichste Weg ist <<"EOF", aber <<E"OF"oder <<""EOFwird es auch tun. Ohne diese envsubstwird die Zeichenfolge mit $bereits erweitert. Da envsubstZeichenfolgen mit Literal- $foooder Teilzeichenfolgen $bearbeitet werden, bedeutet envsubstdas, sie zuvor zu erweitern, nichts. Außerdem wird die Shell in Ihrem Fall höchstwahrscheinlich $zu einer leeren Zeichenfolge erweitert, da die Variablendefinition in Ihrem Code nur envsubstdie Shell selbst betrifft . es sei denn, die Variable mit dem gleichen Namen wurde (versehentlich?) zuvor in der Shell gesetzt.

Nun kommen wir zu Ihrer expliziten Frage. Sie können das Ergebnis an einen beliebigen Befehl weiterleiten, Sie müssen jedoch das endgültige EOF in einer separaten Zeile aufbewahren. 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: $ EOF 

Oder Sie können den Code ausführen, den Sie in einer Subshell haben:

( passphrase=$(<passphrase) envsubst <<"EOF" apiVersion: v1 kind: Secret metadata: name: openshift-passphrase stringData: passphrase: $ EOF ) | oc create -f - 

Hinweis Bash Reference Manual sagt

Jeder Befehl in einer Pipeline wird in einer eigenen Subshell ausgeführt

Selbst in der ersten Lösung, wenn wir es geschafft haben, unsere Pipe ohne zu bauen ( ), |läuft der erste Teil (vorher ) sowieso in einer Subshell. Die zweite Lösung macht diese Subshell explizit. Nachdem wir explizit verwendet haben (, wartet die Shell auf explizit ). Dies ermöglicht uns, nach der Beendigung etwas zu platzieren EOF.

Überraschenderweise können Sie auch bei der ersten Lösung mehrere document ( <<) in einem einzigen zusammengesetzten Befehl verwenden. Solche Weiterleitungen sind in einer Pipe wenig sinnvoll, können aber mit &&und nützlich sein ||.

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

Das gleiche umgeordnet mit expliziten Subshells:

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

Je nach Situation bevorzugen Sie eine Notation vor der anderen.

Zurück zu Ihrem spezifischen Beispiel. Mit einer Subshell benötigen Sie nicht einmal envsubst:

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

Es gibt interessante Unterschiede zwischen diesem Weg und den vorherigen beiden:

  • Dieses Mal ist die Subshell selbst sollte erweitern $, daher <<EOFnicht <<"EOF".
  • Damit dies funktioniert, muss die Variable der Subshell bekannt sein, nicht nur oc; Dies bedeutet … passphrase=$(<passphrase) oc create -f - <<…(beachten Sie das Fehlen eines Semikolons) würde nicht funktionieren.
  • Technisch würde derselbe Code, der nicht in einer Subshell (dh ohne ( )) ist, auch funktionieren, aber dann würde die Variable in der Mainshell bleiben. Wenn Sie den Code in einer Subshell ausführen, stirbt die Variable mit. In Ihrem ursprünglichen Code ist die Variable nicht für die Main-Shell festgelegt. Ich denke, das ist, was Sie wollen.
Danke für die sehr ausführliche Antwort. Ich wünschte, ich könnte es einmal für jeden Teil wählen. simbo1905 vor 5 Jahren 0