「リストコンテキスト」(および「文字列コンテキスト」)は(正確に)何ですか?

「リストコンテキスト」(および「文字列コンテキスト」)は(正確に)何ですか?

私は「リストコンテキスト」と「文字列コンテキスト」が何度も使用されているのを見ました。

私はPerlでそのような説明の使用を知って理解しています。それら$と@に適用されます。

ただし、シェルの説明に使用される場合:


これは、どこにも定義されていないか、せいぜいよく文書化されていない分散用語であるようです。

POSIX にはその定義はありません。Googleによると

これは(したがって、)そのポイントは何ですか? :

つまり、単語のリストやパターンが必要な場合は必ず二重引用符が必要です。パーサーが生の文字列を必要とする状況ではオプションです。

しかし、この用語は使いにくいようです。文字列コンテキストであるかリストコンテキストであるかを確認するために、「結果が必要」のときに「結果が何であるべきか」をどのように見つけることができますか?

それとも正確かつ正確に定義できますか?

答え1

標準シェル言語にはそのような概念はありません。 「コンテキスト」はなく、単にステップを拡張するだけです。

引用符は、生成された単語のトークン化で最初に認識されます。彼らは単語を互いに貼り付けてabc"spaces here"xyz「単語」を形成します。

理解すべき重要な点は、引用文が後続の拡張段階で保存され、元の引用文が拡張に表示される可能性のある引用文とは区別されることです。

パラメータ拡張では二重引用符は考慮されません。ただし、フィールド分割プロセスは後で発生し、これは最初のトークン化に再び続きます。引用符は再分割を防ぎ、再び保持されます。

この分割後、パス名拡張(「globbing」)が発生します。保持された引用符はこれを防ぎます。ワイルドカード演算子は引用符内で認識されません。

最後に、「引用符の削除」という後のステップで引用符が削除されます。もちろん、ただオリジナル引用符!

POSIXはうまくいく導入プロセス理解できる方法で、関係のない概念(誤解を招く)で謎を解こうとすると理解が混乱するだけです。

ゴミを捨てる人アドホック「リストコンテキスト」などの概念は、すべての処理に対して同等の(同じ結果を生成する)完全な代替仕様を提供できるようにアイデアを定式化する必要があります。その後、並列設計間で概念を混在させないでください。 1つの解釈を使用してください。 「リストコンテキスト」または「文字列コンテキスト」は、これらの概念が明確に定義され、処理ステップがそれを中心に構成されるシェル拡張理論では意味があります。

推測すると、「リストコンテキスト」は、シェルがトークン化された単語リスト(2つの単語リストなど)を処理するというアイデアを表します{foo} {abc" x "def}。引用符は2番目の単語の一部ではありません。その内容は、実際にはabc x defスペースの分割を防ぐ意味論的な引用符です。この引用符の中には「文字列コンテキスト」があります。

しかし、これらの拡張ステップを実装することは不可能です。実際に生の引用として識別される引用もありますが、一種のリストデータ構造、つまり引用された部分{foo} {abc" x "def}が他のタイプのノードによって識別される(そして引用が消える)リストのリストです。 Lisp 表記法を使用すると、次のようになります。

(("foo") ;; one-element word
 ("abc" (:dq-str " x ") "def")) ;; three-element word

:dq-strラベルのないノードは、二重引用符で囲まれた領域であるリテラルテキストです。:sq-str単一の参照項目には異なる種類を使用できます。

拡張はこの構造を繰り返し、:dq-str文字列オブジェクト、式、またはその他の項目を見ているかどうかに応じてさまざまな操作を実行できます。:dq-strまたは、ファイル拡張子とフィールド分割が抑制されます:sq-str。しかし、パラメータ拡張する内で発生します:dq-str。 「参照の削除」は、フラグメントを取得し、文字列を連結し、内部リスト構造を平面化し、型インジケータを失う最終パスに対応し、結果は次のとおりです。

("foo"
 "abc x def") ;; plain string list, usable as command arguments

2番目のアイテムは、最初のアイテム("abc" (:dq-str " x ") "def")と最後のアイテムが拡張されています。その項目はリストの直接要素なので、「リストコンテキスト」にあると言えます。そして、中間の内容は式、つまり「(二重引用符)文字列コンテキスト」" x "でラップされます。:dq-str

「リストコンテキスト」で「リスト」が意味するのは、このように明確に定義されたモデルがなければ誰でも推測できることです。主な単語リストですか?それとも単語を表す塊のリストですか?

答え2

あなたが引用した出来事の大部分が私に起こったので、@Gillesの言葉にほとんど頼っていますが、ここに答えを与えなければならないようです。

使ってきたリストコンテキストそしてスカラー/非リストコンテキスト(比較する文字列コンテキスト少なくとも2004年以降は、非リストのコンテキストとして理解されないと、何十回も混乱を招く可能性があります。存在するニュースネットワークまたはUNIXSEほとんどの時間は、Bourneのようなシェルから拡張を引用しないことの効果を議論する記事に割り込まれました。以前に私が意味していたことを明確にするように頼んだ人は覚えていません。多くの場合、この種の背景の例をいくつか説明します。)

私はこれをシェル言語の正式な仕様で使わずに他の人にシェルの動作を説明するのに役立つ英語のテキストです。

それじゃない公式用語これは明らかにperl公式(文書の)用語に触発されたものです。私の前にUnixシェル環境でこれを使った人がいるかどうかはわかりませんが(おそらくそうだったでしょう)、それ以降に使った人は明らかです。私はそれを所有すると主張しません。

リストコンテキスト(少なくともそれが使用されるコンテキストで使用される場合)、単にシェルがコンテキスト内の任意の数の要素を期待することを意味します。しかし、スカラー/非リスト/文字列コンテキストperlほとんどのBourne様シェルでは、これらのリストコンテキストは次のとおりです。

  • 単純なコマンドパラメータ(例:)echo elements
  • for i in elements
  • array=(elements)(および変形+=

一部のシェルには、次の機能があります。

  • cmd < elementszsh(例)しかし、同様のことをします。cat -- elements | cmdnl < *.txtnl < {foo,bar}.txtnl < foo.txt < bar.txt
  • cmd > elements(および>| >>...のバリエーション)zsh次のようなことを行います。cmd | tee -- elements
  • elements() { code; }zsh一度に1つ以上の機能を定義します(または次の場合要素空のリストに解析します(リテラル() { echo x; }匿名関数)).
  • compound=(foo=(elements) elements)または等。matrix=((elements) (elements))ksh93
  • など。

この場合、globは通常拡張され、分割+globを適用したくない場合は拡張を参照する必要があります(または/ sh互換オプションを有効にしない限り、zshnullを削除するだけです)。shwordsplitglobsubst

たとえば、交換した場合要素*.txt上記の例では、*.txt現在のディレクトリのtxtファイルのリストが展開されています。

POSIX仕様でそれに対応する項目を探している場合は、globが拡張されるコンテキストを探してください。 POSIX、少なくとも1つのインスタンスはそれを呼び出します。フィールド分割が行われるコンテキスト(実際には後にフレーズが変更されました。以前のフレーズについてオースティングループに問題を提起しました。)。もちろん、この表現は次の質問に答えるのにあまり役に立ちません。フィールド分割を実行する場所

これスカラーコンテキスト別の文脈であろう。

存在する

scalar=*.txt
case *.txt in...
[[ -f *.txt ]]

*.txtシェルは単に期待しているので拡張できません一つひも。

cmd > *警告/制限事項として、これらの用語は、/(POSIXモードではない場合)、(構文の代わりに使用)、または(一部と対話する場合のみ)など、シェルで何が起こるのかを明確に捉えません。もう一つcmd > ~(N)patterna=(); b=; c=(a b); d=*; IFS=:; e=a:b; cmd 1> "${a[@]}" 2> $b 3> "${c[@]}" 4> $d 5> $ebashyashksh88set -Avar=(...)ksh93リストコンテキスト1つの要素を含むリストのみが必要です(分割とワイルドカードは場合によっては動作が異なります)。

答え3

これ馬の種「リストコンテキスト」と「文字列コンテキスト」はPerlに由来していますが、同様の概念がシェル言語にも当てはまります。参考にしてください似たような概念:コンテキストの種類とコンテキストの種類によって結果が異なります。

この言葉コンテキストプログラミング言語の意味に関する技術用語です。それ精密意味は、この回答の範囲外の意味論の特定の形式化に関連付けられています。これ認識意味は、コードを取り巻く環境の特性です。たとえば、コードスニペットが$foo異なる状況で異なる意味を持つということは、埋め込まれたプログラムの動作がプログラムに表示される内容の性質$fooに依存することを意味します。$foo

シェルの意味は非常に複雑です。これは、プログラミング言語入門教科書の伝統的なカテゴリには適合しません。シェルプログラムの実行は2段階に分けることができます。 (これは意味を表現する方法であり、シェルインタプリタがこれをこのように分割しなければならないという意味ではありません。)

  1. 解析ステップでは、文字列(ソースファイルの内容またはパラメータの内容-c)を抽象構文ツリーに変換します。内部にPOSIX仕様、これはステップ2と3(マーカーの識別と解析)に対応します。 POSIX仕様の定義文法規則木の形を描いてみてください。これは文脈自由文法ではないことに注意してください。デモは文脈自由文法の一般的なデモンストレーションに基づいていますが、「ルールの適用」という説明があります。窒素これをより複雑な数学的オブジェクトにします。

  2. 実行フェーズでは、ツリーノードに対していくつかの評価を実行し、外部コマンドを呼び出します。 POSIX仕様では、これはステップ4〜7(拡張、リダイレクト、コマンドの実行、待機)に対応します。

拡張WORDPOSIXが「単語」と呼ばれる抽象構文ツリーの特定の種類のノードに適用されるプロセス。 2つのグループに分けることができます。

  1. POSIX 用語では、最初の拡張セットには以下が含まれます。チルダ拡張(例:~foo/home/foo)、パラメータ拡張(たとえば、$foobar値が次の場合)、foobarコマンドの置き換え(例:$(foo)barコマンド出力が次の場合foobar算術拡張(例:$((2+2))4)。最初の拡張セットは、一重引用符内にあるか、バックスラッシュが先頭にある「引用符」で囲まれた文字を除くすべての単語に対して実行されます。この拡張セットの出力は、ほぼコメント付きの文字列です(おおよその内容は以下で説明します)。

  2. 2 番目の拡張セットには次のものが含まれます。フィールド分割そしてパス名拡張(しばしば「ファイル名の生成」または「ワイルドカード指定」と呼ばれます)この拡張セットは、コメント付きの文字列を文字列のリストに変換します。この拡張セットは、最初のセットが実行される位置のサブセットで実行されます。二重引用符で囲まれた単語部分では実行されません。単語が抽象構文ツリーのどこかにある場合、まったく実行されません。。これがリストと文字列のコンテキストが入る場所です。特定のコンテキスト、すなわち抽象構文ツリーの特定の位置カテゴリに対して、第2の拡張セットが実行される。これらはすべてリストコンテキスト、拡張プロセスの結果が(文字列)リストであるため、そのように名前が付けられました。他の場合には、次のように呼ばれる。文字列コンテキスト、2番目の拡張セットは実行されず、拡張プロセスの結果は単一の文字列です。

POSIXの説明見積もりの​​削除最後の拡張ステップと同じです。これは参照を解釈する1つの方法であり、フィールド分割前のすべての拡張は文字列から文字列への変換として定義されます。たとえば、単語が与えられ、変数の値が'$foo'$bar\$quxと仮定すると、パラメータbar拡張valueはそれをに変換しますが、'$foo'value\$qux他の最初の拡張セットは文字列を変更せずに残します。見積もりの​​削除最後に見積もりを削除して$foovalue$qux

引用符の削除デモでは、すべてのステップで引用符の一致を実行する必要があります。より簡単に従い、実装し、同じ最終結果を提供するデモは、部品リストを生成する逆参照ステップを実行することです。各セクションには、参照するかどうかを覚えるためにコメントがあります。たとえば、quoted、unquoted変数の拡張、quoted、naked、naked、nakedを'$foo'$bar\$qux逆引用符で表示します。 (割り当ての識別やエイリアス拡張の有無の決定などの操作では、「参照」と「ネイキッド」を区別する必要があります。)2段階の拡張は、リストコンテキストの参照されていない部分でのみ発生します。$foobar$qux

POSIX は、拡張フェーズを明示的にリストして、2 番目の拡張セットが発生するかどうかを指定します。たとえば、「すべての変数割り当てには、値を割り当てる前にチルダ拡張、パラメータ拡張、コマンド置換、算術拡張、および引用符の削除が必要です。」これをより簡単に説明すると、最初の拡張セットだけが発生するということです。つまり、割り当ては文字列コンテキストです。拡張実行用のルールセットは2つだけなので、コンテキストも2つしかありません。つまり、最初のセットのすべてのルールが実行されるか(文字列コンテキスト)、両方のセットが順次実行されます(リストコンテキスト)。

case(実際に完全性を期すために、3番目の種類のコンテキストであるパターンコンテキストがあります。caseパターンでは、最初の拡張セットのみが実行されますが(文字列コンテキストと同様)、2番目の拡張セットの一部は次のとおりです。関連 - 引用符なしワイルドカード文字は、文字列一致のためのワイルドカード文字です。

言語定義は、どのコンテキストがリストコンテキストであり、どのコンテキストが文字列コンテキストであるかを指定します。原則として、これは任意です。しかし、その背後には直観があります。文法にトークンリストが必要な場合は、WORDそのトークンに対して2番目の拡張セットが実行され、文法に単一のリストが必要な場合は2番目の拡張セットは実行されませWORDん。これを説明する簡単な方法は、文法にリストが必要な場合はリストコンテキスト、文法に単一の文字列が必要な場合は文字列コンテキストです。

関連情報