bash で : <<'END' は複数行のコメントブロックを作成するためにどのように機能しますか? 質問する

bash で : <<'END' は複数行のコメントブロックを作成するためにどのように機能しますか? 質問する

素晴らしい答えを見つけましたbash スクリプトのコメント(によるフォロー):

#!/bin/bash
echo before comment
: <<'END'
bla bla
blurfl
END
echo after comment

区切り文字の前後のand'は重要です。そうでない場合、たとえばブロック内のものが解析され、実行されます。'END$(command)

これは見苦しいかもしれませんが、機能しており、その意味を知りたいです。誰か簡単に説明できますか? :no-op または true であるという説明はすでに見つけました。しかし、いずれにしても no-op または true と呼ぶことには意味がありません...

ベストアンサー1

この説明は「簡単」というより「徹底的」なものになると思いますが、それでは始めましょう。

コメントの目的は、ないコードとして解釈または実行されます。

もともとUNIXシェルにはコメント構文がなかったそれ自体ただし、ヌル コマンド:(かつてはディスク上の実際のバイナリ プログラム/bin/:) はありました。このコマンドは引数を無視し、呼び出し元のシェルに実行が成功したことを示す以外は何も行いません。実質的には、これは単語ではなく句読点のように見える の同義語なのでtrue、スクリプトに次のような行を追加できます。

: This is a comment

これは従来のコメントとは異なり、シェルが実行する実際のコマンドです。しかし、コマンドはする何でも、きっと十分近いでしょう。ミッションは達成されました! そうでしょう?

問題は、その行が単にコマンドとして実行されるだけでなく、依然としてコマンドとして扱われることです。最も重要なのは、無視されるはずの引数に対しても、字句解析 (パラメータの置換、単語の分割など) が依然として実行されることです。このような処理は、"コメント" の構文エラーによってスクリプト全体がクラッシュするリスクがあることを意味します。

 : Let's see what happens next
 echo "Hello, world!"
 #=> hello.sh: line 1: unexpected EOF while looking for matching `''

この問題により、今ではおなじみの本物のコメント構文が導入されました#(BSD で作成された C シェルで初めて導入され、その後、vanilla sh に借用されました)。 から#行末までのすべてがシェルによって完全に無視されるため、構文の妥当性を気にせずに好きなものをそこに記述できます。

 # Let's see what happens next
 echo "Hello, world!"
 #=> Hello, world!

そしてそれはシェルのコメント構文の誕生

/*しかし、あなたが探していたのは、C や Java で によって導入され、 で終了するタイプの複数行 (ブロック) コメントです*/。残念ながら、シェルにはそのような構文がありません。連続した行のブロックをコメント アウトする通常の方法 (私が推奨する方法) は、#各行の前に を置くことです。しかし、これは確かに「複数行」のアプローチではありません。

シェルは複数行の文字列リテラルをサポートしているので、:次のような文字列を引数として使用できます。

: 'So
this is all
a "comment"
'

しかし、これには単一行の場合と同じ問題がすべてあります:。 1 つの長い文字列ではなく、各行の末尾にバックスラッシュを使用して、複数の引数を持つ長いコマンド ラインを作成することもできますが、#先頭に を置くよりもさらに面倒で、末尾の空白によって行の継続が中断されるため、より脆弱です。

あなたが見つけた解決策は、いわゆるヒアドキュメント構文によりsome-command <<whatever、コマンドの直後の行から、テキストのみを含む次の行までのテキスト行がwhatever読み取られ、 の標準入力として に送られます。次に、この機能を利用した、通常の ベースのシェル実装の「Hello, world」some-commandの代替例を示します。echo

cat <<EOF
Hello, world
EOF

catを私たちの古い友人に置き換えると:、引数だけでなく入力も無視されることがわかります。つまり、何でも好きなものを入力できますが、それでも何も行われません (そして、何も正常に行われなかったことが示されます)。

ただし、ヒアドキュメントの内容は文字列処理の対象となります。そのため、単一行:コメントの場合と同様に、ヒアドキュメント バージョンでは、実行可能コードではないコード内で構文エラーが発生するリスクがあります。

#!/bin/sh -e 
: <<EOF
(This is a backtick: `)
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> ./demo.sh: line 2: bad substitution: no closing "`" in `

解決策は、あなたが見つけたコードに見られるように、ヒアドキュメントを導入する行 (例 ) でドキュメントの終わりの「センチネル」(またはなど) を引用符で囲むことですEOFENDこれ<<'EOF'を行うと、ヒアドキュメントの本体全体がリテラルテキストとして扱われ、パラメータの展開やその他の処理は行われません。代わりに、テキストは、ファイルから読み取られるのと同じように、変更されずにコマンドに渡されます。したがって、センチネルのみで構成される行を除いて、ヒアドキュメントには任意の文字を含めることができます。

#!/bin/sh -e
: <<'EOF'
(This is a backtick: `)
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> In modern shells, $(...) is preferred over backticks.

(注目すべきは、方法センチネルを引用符で囲むかどうかは関係ありません。 、 、 ; も使用できます<<'EOF'<<E"OF"すべて<<EO\F同じ結果になります。これは、Perl や Ruby などの他の言語でのヒアドキュメントの動作とは異なります。他の言語では、センチネルを引用符で囲む方法に応じてコンテンツが異なる方法で処理されます。

上記のいずれにも関わらず、#コメントアウトしたい各行の先頭に を置くことを強くお勧めします。適切なコード エディターであれば、この操作は簡単に行えます (古いものでもvi)。また、コードを読む人が、結局のところ、読者の利益のためにドキュメント化されることを意図している部分で何が起こっているのか理解するためにエネルギーを費やす必要がなくなるという利点もあります。

おすすめ記事