パイプの途中で「ヒアドキュメント」を使用するにはどうすればよいでしょうか?

パイプの途中で「ヒアドキュメント」を使用するにはどうすればよいでしょうか?

ヒアドキュメントをテンプレートとして使用してコンテンツを生成したいと考えています。

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$foo${foo}envsubst${passphrase}envsubst

ここで、明確な質問に移ります。結果を任意のコマンドにパイプすることができますが、最後の EOF を別の行に保持する必要があります。これを行う 1 つの方法は次のようになります。

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

または、サブシェルにあるコードを実行することもできます。

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

注記Bash リファレンスマニュアル言う

パイプライン内の各コマンドは、それぞれのサブシェルで実行されます。

したがって、最初のソリューションでも、 を使用せずにパイプを構築できたとしても( )、その最初の部分 ( の前|) はいずれにしてもサブシェルで実行されます。2 番目のソリューションでは、このサブシェルを明示的にします。explicit を使用した後(、シェルは明示的な を待機します)。これにより、終了する の後に何かを配置できるようになりますEOF

驚くべきことに、最初のソリューションでも、1 つの複合コマンドで複数のヒア ドキュメント ( ) を使用できます。このようなリダイレクトはパイプではほとんど意味がありませんが、および<<では役立つ場合があります。&&||

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

明示的なサブシェルを使用して同じものを並べ替えます。

( 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
)

この方法と前の 2 つの方法の間には興味深い違いがあります。

  • 今回はサブシェル自体が拡張されるはずなので${passphrase}、 では<<EOFありません<<"EOF"
  • これが機能するには、変数が だけでなくサブシェルにも認識されている必要がありますoc。つまり、… passphrase=$(<passphrase) oc create -f - <<…(セミコロンがないことに注意してください) は機能しません。
  • 技術的には、サブシェルにない (つまり なし( )) 同じコードも機能しますが、その場合、変数はメインシェルに残ります。サブシェルでコードを実行すると、変数もそれとともに消滅します。元のコードでは、変数はメインシェル用に設定されていないため、これが必要な状態だと思います。

関連情報