web-dev-qa-db-ja.com

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

Ash、dash、bashでは、実行すると

$ echo ab$

戻る

ab$

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

17
Harold Fischer

_$_自体には特別な意味はありません(_echo $_を試してください)。その後に他の文字を組み合わせて、展開を形成する場合のみです。 _$var_(または_${var}_)、$(util)$((1+2))

_$_は、POSIX標準のセクション Token Recognition で拡張を定義するという「特別な」意味を取得します。

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

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

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

これは_ab$_文字列をカバーしています。

単独の_$_の場合(「新しい単語」はそれ自体で_$_になります):

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

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

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

10
Kusalananda

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

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


トークン化

POSIXトークン化には以下が必要です a $は有効な開始ではありません パラメータ展開コマンド置換 、または 算術置換 は、構築されるWordトークンのリテラル部分と見なされます。これは、ルール5(「現在の文字が引用符で囲まれていない$または`の場合、シェルは、引用符で囲まれていない紹介文字から、パラメーター展開、コマンド置換、または算術展開の候補の開始を識別するものだからです。シーケンス:$または${$(または`、および$((] ")は適用されません。これらの拡張はそこでは実行できないためです。パラメータの展開では、有効な名前をそこに表示する必要があり、空の名前は無効です。

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

echo a$+bは特別なパラメータの名前ではないため、同じ亀裂に陥る+という形式の3番目のケースもあります。これは、ルールのさまざまな部分をトリガーするため、後で戻ります。

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


単語拡張

この方法で入力が解析された後、$がWordに含まれていると、読み取られた各単語に Wordの展開 が適用されます。各単語は個別に処理されます

それが指定されている

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

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

結果は不定です。

「未指定」とは、ここで特定の用語であり、

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

あなたの例では、echo ab$$の後にany文字したがって、このルールは適用されず、指定されていない結果は呼び出されません。 $によって引き起こされる拡張はないため、文字どおり存在し、出力されます。

それが当てはまる場所は、上から3番目のケースです:echo a$+b。ここで$の後には+が続きますが、これは数値ではない特別なパラメータ(@*#?-$!、または0)、変数の開始 name (アンダースコアまたは ポータブル文字セットのアルファベット) )、または角括弧の1つ。この場合、動作は指定されていません。準拠するシェルは、+という特別なパラメーターを展開するために許可され、準拠するアプリケーションシェルがそうではないと仮定しないでください。シェルは、エラーの報告を含め、他に好きなことをすべて実行できます。

たとえば、POSIXモードを含むzshは $+bを "is variable b set" として解釈し、その場所を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":不特定の動作

Wordの最後の$の場合、動作に依存することが許可されており、文字どおりに処理し、引数の一部としてechoコマンドに渡す必要があります。これはシェルの適合要件です。

7
Michael Homer