bashは三重括弧をどのように解釈しますか?

bashは三重括弧をどのように解釈しますか?

Bashでコマンドを表示します。

echo $(((i=18)))

18を印刷してください。これは $((((i=18))) が算術拡張として解釈されることを理解します (変数 i はコンストラクタ内で初期化されます)。ただし、コマンドの置き換えを検討することもできます。

$(command)

そして

((i=18))

はいcommand、実際にはコマンド置換が出てきそうです。今後算術拡張(bashシェルを学ぶ、オライリー2005、17ページ。 181)。したがって、結果は期待したものとは異なります。これをどのように説明しますか?

答え1

ワット。$(((i=18)))、あなたは正しいです。$(( (i=18) ))、または$( ((i=18)) )その両方が有効です。やや一般的です(確かにシンプル)これらのあいまいな状況を説明する方法は、最も長い有効な演算子を識別することです。これは、それが$((次のものとして解釈されるという意味です(

たとえば、BashとKshで何が起こるかは次のとおりです<<(<<後ろにはありますが、後ろには(ありません。<<(最初の説明は文法エラーですが、2番目の説明は有効です!ユーザーはシェルが見つかるようにスペースを追加する必要があります。同様に、i+++aはい。i++ + aそしていいえi + ++a。他の言語にも同様の状況があります。

しかし、その場合、$(((これは完全に真実ではありません。一部の殻はより遠く離れているように見えますが、一部はそうではありません。たとえば、次のことを考えてみましょう。

echo $((echo hi); (echo ho))

コマンドの一般的な解釈は有効で、印刷しますhi ho。しかし、貪欲な認識は$((これを算術拡張として解釈するので、完全に偽です。

DashとBusyboxを除いて、私が試したすべてのシェルは有効なコマンド置換を認識します。最初の2つの括弧の間にスペースを入れると明確になります。

実際には、オペレーション拡張の前にコマンド置換が発生しているようです。

いいえ、同じ処理ポイントで発生します。これを確認するには、有効な算術拡張で拡張されるコマンド置換を作成します。たとえば、echo '$((1+2))'print $((1+2));$( echo '$((1+2))' )に拡張されますが、$((1+2))同じコマンドでは処理されません。

これ、

echo $( echo '$((1+2))' )

$((1+2))代わりに出力します3

もちろん、算術拡張は数字しか生成できないため、逆順はテストできません。ただし、変数/引数拡張とコマンド置換との間で同様の実験を実行できますが、いずれの場合でも、1回の拡張結果はもはや拡張されません。


サポート拡張一方、それは違います。

Bash は、変数が拡張される前に変数を処理します。

$ bash -c 'v=000 va=123 vb=456; echo $v{a,b}; n=1 m=4; echo {$n..$m}'
123 456
{1..4}

Kshの場合はその逆です。

$ ksh -c 'v=000 va=123 vb=456; echo $v{a,b}; n=1 m=4; echo {$n..$m}'
000a 000b
1 2 3 4

(Kshでは中a="{1.."; b="4}"; echo $a$b括弧も拡張されて印刷されます1 2 3 4。Zshはここでも正当であるため、変数を最初に拡張しますが、拡張中括弧が追加の拡張をトリガーすることはできません。Zshも<<(これを認識します< <(。)

もちろんあります。噴射とファイル名の生成、ここで発生する結局、結果だけのために引用しないズーム。

答え2

この動作は、次の説明と一致します。バッシュ変更ファイル:

$((...))Posixが要求するように、潜在的にネストされたコマンド置換ではなく、常に算術拡張を最初に解決します。

もちろん、POSIXが認識されましたあいまいな点がある場合は、算術拡張が優先されます。

シェルコマンド言語の構文は、$((""で始まる拡張についてあいまいです。これは、サブシェルで始まる算術拡張またはコマンド置換を導入できます。算術拡張が優先されます。つまり、シェルは拡張を算術拡張で解決できるかどうかを最初に決定し、拡張を算術拡張で解決できないと判断した場合は、拡張をコマンドの大部分だけで解決する必要があります。

今、文のいくつかの単語「算術拡張の前に命令の置き換えが来るようです」:いいえ、POSIXの指定単語拡張は、最初から最後まで、すなわち、現れる順番で左から右に行われる。

チルダ拡張、パラメータ拡張、コマンド置換、および算術拡張は、最初から最後まで実行する必要があります。

これ「トークン認識」セクションいくつかの追加の精度が提供されます。

現在の文字が引用符のない '$' または ''' の場合、シェルは引用符のない導入文字シーケンス '$' または '${' でパラメータ拡張、コマンド置換、または算術拡張の候補の開始を識別しますする必要があります。 、または "$(" または "`" および "$((") のそれぞれ) シェルは、拡張するデバイスの終端を決定するのに十分な入力を読み取る必要があります。

関連情報