POSIXは、コマンド置換内の引用されたヒアドキュメントに何を必要としますか?


20

、この質問の誰かが使用して問題を報告し、ここで文書を内部に引用された区切り文字の単語で$(...)コマンド置換バックスラッシュ、\文書トリガーの内部の行末の改行結ぶラインの継続が、ここでは同じながら、文書予想通りコマンド置換の作品を。

簡単なドキュメントの例を次に示します。

cat <<'EOT'
abc ` def
ghi \
jkl
EOT

これには、行末に1つのバックティックと1つのバックスラッシュが含まれます。区切り文字は引用符で囲まれているため、本体内で展開は発生しません。すべてのBourne-alikesで、これはコンテンツを逐語的に出力します。次のようにコマンド置換内に同じドキュメントを配置した場合:

x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"

その後、それらは同じ動作をしなくなります。

  • dashashzshksh93、BusyBoxのはashmksh、とSunOS 5.10 POSIXは、sh以前のように、すべて、文書の逐語的な内容を与えます。
  • Bash 3.2では、一致しないバックティックに対して構文エラーが発生します。一致したバックティックを使用して、コマンドとしてコンテンツを実行しようとします。
  • Bash 4.3は、「ghi」と「jkl」を1行にまとめますが、エラーはありません。--posixオプションでは、この影響を与えません。Kusalananda pdksh、同じように振る舞うと言っています(ありがとう!)

元の質問で、これはBashのパーサーのバグだと言いました。それは...ですか?[更新:yes ] POSIXからの関連テキスト(すべてシェルコマンド言語定義から)は、次のとおりです。

  • §2.6.3コマンドの置換

    $(command)形式では、開き括弧から対応する閉じ括弧までのすべての文字がコマンドを構成します。commandには、任意の有効なシェルスクリプトを使用できます。ただし、不特定の結果を生成するリダイレクトのみで構成されるスクリプトは除きます。

  • §2.7.4ヒアドキュメント

    単語の一部が引用されている場合、区切り文字はwordの引用削除を実行して形成され、ヒアドキュメントの行は展開されません。

  • §2.2.1エスケープ文字(バックスラッシュ)

    <バックライン>の後に<改行>が続く場合、シェルはこれを行の継続と解釈します。<backslash>と<newline>は、入力をトークンに分割する前に削除されます。

  • §2.3トークンの認識

    場合io_hereトークンが文法によって認識されている(シェル文法を、一つ以上のすぐ隣次以降の行の)改行が一つ以上のここで、ドキュメントの本体を形成トークンとの規則に従って解析されなければなりませんHere-ドキュメント

    io_hereを処理していない場合、シェルは、入力内の次の文字に以下の最初の適用可能なルールを適用することにより、入力をトークンに分割します。...

    ...

    1. 現在の文字が<バックスラッシュ>、一重引用符、または二重引用符であり、引用されていない場合、引用されたテキストの最後までの後続の文字の引用に影響します。引用のルールは、引用で説明されています。トークンの認識中、実際には置換は行われず、結果のトークンには、入力に含まれる文字(<newline>を除く)が含まれます。引用テキストの。

これについての私の解釈は$(、終了するまでのすべての文字が)逐語的にシェルスクリプトを構成するということです。ヒアドキュメントが表示されるため、ヒアドキュメントの処理は通常のトークン化の代わりに行われます。ヒアドキュメントには、引用符で囲まれた区切り文字があり、その内容は逐語的に処理されます。エスケープ文字が含まれることはありません。しかし、このケースは単に対処されておらず、両方の動作が許容されるという議論を見ることができます。関連するテキストをどこかでスキップした可能性もあります。


  • この状況は他の場所でより明確になっていますか?
  • (理論上)移植可能なスクリプトは何に依存できるはずですか?
  • これらのシェル(Bash 3.2 / Bash 4.3 /その他すべて)の特定の処理は、規格で義務付けられていますか?禁止?許可?

2番目のケースで出力を生成する方法を教えてください。
ジュリーペレティエ

@JuliePelletier echo "$x"ですが、変数を検査するあらゆる方法が機能します。その行を下に編集しました。
マイケルホーマー

2
簡単に修正できるようです。このパッチは少なくとも動作するようです:ignore_quoted_newline_in_quoted_heredoc.patch
geirha

1
あなたはこれを正しく解釈しており、標準はかなり明確だと思います。コマンド[...] "それで、サブシェルでコマンドを実行し、$(...)その出力に置き換えます...ここで、サブシェルでサンプルのコマンドを実行すると(bash)、期待される結果が出力されます。「ghi」と「jkl」を折りたたむのは、コマンド置換に変換するときだけです。だから、これはバグ
imo

2
@geirha Bashのバグを報告しまし。現在のメンテナンスの影すら見えないので、私はpdkshについて気にしません。
マイケルホーマー

回答:


5

これはBashのメーリングリストで尋ねられ、メンテナはそれがバグであることを確認しました

彼らはまた、POSIXのテキストは「必ずしも曖昧ではないが、よく読む必要がある」と述べたので、それについての明確化を求めた。問題の説明と規格の解釈を含む彼らの答えは以下の通りでした:

コマンド置換は、赤いニシンです。バグがどこにあるかを指摘したという点でのみ意味があります。

ヒアドキュメントの区切り文字は引用符で囲まれているため、行は展開されません。この場合、シェルは、引用されているかのように入力から行を読み取ります。引用符で囲まれたコンテキストでバックスラッシュが表示される場合、エスケープ文字として機能せず(以下を参照)、バックスラッシュと改行の特別な処理は行われません。実際、区切り文字の一部が引用符で囲まれている場合、ヒアドキュメントの行は単一引用符で囲まれているように読み取られます。

Posix 2.2.1のテキストは不自然に書かれていますが、バックスラッシュは引用符で囲まれていない場合にのみ特別に扱われます。バックスラッシュを引用し、単一引用符または別のバックスラッシュのみですべての展開を禁止できます。

読みやすい部分は、単一引用符を意味する「展開されていない」テキストです。規格では、2.2でヒアドキュメントは「別の形式の引用」であると述べていますが、単語がまったく展開されない唯一の引用形式は単一引用符です。したがって、これは単一引用符ではなく、単一引用符とまったく同じような引用形式です。


@Scott(1)これはすべての質問に答えるものであり、余分なものはないと思います。答えから始まる私のコメントは、状況を誤解したモデレーターによって行われた削除に関するものです。(2)十分な評判がありません。(3)回答を削除した人が同じような行動をしたことはありがたかったのですが、今後もそのことを忘れないでください。考えてくれてありがとう。
ケビン

私のポイントは、あなたの最初の段落のほとんどがマイケル・ムロゼクとの会話であり、質問への答えではないということでした。投稿にコメントするのに十分な評判がないことは承知していますが、メタやチャットには十分だと思います。
スコット

1
@Scott私はあなたが答えを合理化しようとしていることを理解し感謝していますが、正確に合理化された答えを以前に投稿しました(引用とそのリンクのみ)、それはモデレーターによって削除されました(議論なし!)削除された投稿にはチャットやその決定に異議を唱えるリンクはありません。彼の根拠のない批判に答えることで、それが削除を生き延び、質問者に受け入れられ、そして私が答えを修正して前文を削除することを望みました。
ケビン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.