POSIXシェル:単語の最後の文字である場合、「$」は特別な意味を失いますか?


17

灰、ダッシュ、バッシュ、私が走るとき

$ echo ab$

それは戻ります

ab$

この動作はPOSIXで指定されているのですか、それともPOSIX準拠のシェルでの一般的な規則ですか?POSIXシェルコマンド言語のページで、この動作について言及しているものは見つかりませんでした。


4
より良い質問は、「単語の最後の文字である場合、特別な意味を$ 獲得しますか?」です。に割り当てられる単一の特別な意味はありません$。パラメータ展開${...}、コマンド置換$(...)、算術式など、複数の異なる展開を導入するために使用されます$((...))。一部のシェルは、kshコマンドの代替バリアントx=${ echo foo; echo bar;}$(...)サブシェルでコマンドを実行しないという点で標準とは異なります)などの追加のコンテキストを導入します。
chepner

@chepner IssacとMichael Homerの意見の違いを検討してみませんか?彼らの答えは明確に矛盾しています
ハロルドフィッシャー

1
マイケル・ホーマーの解釈に同意します。シェルは、構文解析が完了するまで展開について心配することさえ開始しないので、単一の単語ab$$は、元の入力文字列のヌル文字またはケースのスペースが「続く」かどうかにかかわらず、次の文字はありませんのようなecho ab$ foo; 元の引用符で囲まれていない空白は認識され、解析後に破棄されました。
chepner

回答:


10

$後に特別な意味はありません(try echo $)。その後に他の文字と組み合わせて展開を形成する場合のみ$var(例:(または${var}))、$(util)$((1+2))

$セクションの下のPOSIX標準で拡張定義するものとして意味の「特別な」なるトークンの認識は

現在の文字が引用符で囲まれてい$ないまたはである`場合、シェルは、引用符で囲まれていない導入文字シーケンスからパラメータ展開、コマンド置換、または算術展開の候補の開始を識別します:$または${$(または`、および$((。シェルは、拡張されるユニットの終わりを決定するために十分な入力を読み取るものとします(引用されたセクションで説明されているように)。文字の処理中に、展開内または引用符のインスタンスが置換内にネストされている場合、シェルは、見つかった構造に対して指定された方法でそれらを再帰的に処理します。埋め込み構造を認識するために必要な再帰を可能にする置換の先頭から末尾までに見つかった文字は、埋め込みまたは囲みの置換演算子または引用符を含め、結果トークンに変更なしで含まれます。トークンは、置換の終了までに区切られません。

したがって、$展開を形成しない場合、他の解析ルールが有効になります。

前の文字が単語の一部であった場合、現在の文字がその単語に追加されます。

これでab$文字列がカバーされます。

孤独の場合$(「新しい単語」は$それ自体です):

現在の文字は、新しい単語の始まりとして使用されます。

標準の拡張ではないa を含む生成された単語の意味は、$POSIXによって未指定として明示的に定義されます。

また、はの$最後の文字です$$が、これは現在のシェルのPIDを保持する変数でもあることに注意してください。履歴展開(前のコマンドAF最後の引数)を呼び出すことができます。したがって、一般に、いいえ、引用されていない単語の終わりに意味がないわけではありませんが、単語の終わりには少なくとも標準的な拡張を意味しません。bash!$$


7

正確な状況に応じて、これは明示的に指定されていない(したがって、実装は必要に応じて行うことができます)か、観察したとおりに実行する必要があります。あなたの正確なシナリオではecho ab$POSIXはあなたが観察した出力 "ab $"を義務付けており、それは不特定ではありません。すべての異なるケースの簡単な要約は最後にあります。

2つの要素があります。最初に単語にトークン化し、次にそれらの単語を解釈します。


トークン化

POSIXのトークン化は、その必要$の有効な開始ないというパラメータ展開コマンド置換、または算術置換のリテラルの一部とみなされるべきWORD構築トークンされています。ルール5は、(「現在の文字が引用符で囲まれていない場合にはこれはある$`:、シェルはその入門引用符で囲まれていない文字列からパラメータ展開、コマンド置換、または算術拡張のための任意の候補の開始を識別しなければならない$${$(または`、そして$((それぞれ、」 )は適用されません。これらの拡張はいずれも実行可能でないためです。パラメーター展開には、そこに表示される有効な名前が必要であり、空の名前は無効です。

このルールは適用されなかったため、適用されるルールが見つかるまでフォローを続けます。2つの候補は、#8(「前の文字が単語の一部だった場合、現在の文字がその単語に追加される」)と#10(「現在の文字が新しい単語の始まりとして使用される」)です。 、それぞれに適用さecho a$echo $ます。

また、特別なパラメーターの名前ではないecho a$+bため、同じ亀裂を通過するフォームの3番目のケースがあり+ます。これは、ルールのさまざまな部分をトリガーするため、後で戻ります。

したがって、仕様で$は、構文的に単語の一部と見なす必要があり、後でさらに処理することができます。


単語拡張

このように入力が構文解析された後、$単語に含まれている場合、読み取られた各単語に単語拡張が適用されます。各単語は個別に処理されます

以下が指定されています。

引用符で囲まれていない「$」の後に、次のいずれでもない文字が続く場合:

  • 数字
  • 特殊なパラメータの1つの名前(参照特殊パラメータを
  • 変数名の有効な最初の文字
  • A <left-curly-bracket>( '{')
  • A <left-parenthesis>

結果は不定です。

「指定なし」は、ここで特定の用語です

  1. この場合、適合シェルは任意の動作を選択できます
  2. 適合アプリケーションは特定の動作に依存できません

あなたの例では、echo ab$$ が続いていない任意の文字、このルールが適用されないので、不特定結果が呼び出されません。によって引き起こされる拡張はない$ため、文字通り存在し、印刷されます。

それはどこでしょう:上から私たちの第三の場合には、ISを適用しますecho a$+b。ここで$続いている+(番号、特殊パラメータされていない、@*#?-$!、または0)、可変の開始(下線またはアルファベットからポータブル文字セット)、又はブラケットのいずれ。この場合、動作は指定されて+いません:適合シェルexpand と呼ばれる特別なパラメータを作成することが許可されており、適合アプリケーションはシェルがそうしないと仮定してはなりません。シェルは、エラーの報告など、好きなことを何でも行うことができます。

たとえば、POSIXモードに含まれるzshは、「変数セットである」解釈$+bb、その場所を1または0に置き換えます。同様に、~との拡張子があり=ます。これは適合動作です。

これが起こる可能性のある別の場所はecho "a$ b"です。繰り返しますが、シェルは希望どおりに実行できます。スクリプトの作成者は、$リテラル出力が必要な場合はエスケープする必要があります。そうでない場合、動作する可能性がありますが、それに依存することはできません。これは仕様の絶対的な文字ですが、この種の粒度が意図または考慮されたとは思いません。


要約すれば

  • echo ab$:リテラル出力、完全指定
  • echo a$ b:リテラル出力、完全指定
  • echo a$ b$:リテラル出力、完全指定
  • echo a$b:パラメーターの展開b、完全指定
  • echo a$-b-完全に指定された特殊パラメーターの展開
  • echo a$+b:不特定の動作
  • echo "a$ b":不特定の動作

以下のために$単語の終わりに、あなたは動作に依存することは許可されており、それは文字通り扱われ、に渡されなければならないecho、その引数の一部としてコマンド。これは、シェルの適合要件です。


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
テルドン

@MichaelHomer echo $もリテラルで完全に指定されますか?
ハロルドフィッシャー

@HaroldFischerはい
マイケル・ホーマー

どこでやるecho "$"echo "a b$"秋?
ハロルドフィッシャー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.