Bash: 算術展開、パラメータ展開、カンマ演算子

Bash: 算術展開、パラメータ展開、カンマ演算子

カンマ式内、算術式内の bash のパラメータ展開について質問があります。同等であるはずの 2 つのステートメントがありますが、実際はそうではありません。

なぜbashラインは

n=3; k=10; echo $((n++,k=$n))

3?の代わりにを出力します4(予想どおりnに設定されますが、に設定されます。)4k3

対照的に、bashライン

 n=3; k=10; echo $((n++,k=n))

4予想どおり、を出力します。 (nは に設定され4、も に設定kされます4。)

n++両方の bash 行で をに++n、 を にn=n+1、 を に置き換えてみましたn=$((n+1))が、すべて同じ矛盾が生じます。つまり、すべてのスクリプトでk=$nが生成され、すべてのスクリプトでが生成されます。3k=n4


私の理解では、 の値がn整数である場合 (実際そうです)、$nと はn算術式内で同じ値を持つ必要があります。 (そして、これは構造上算術式です(( ... ))。) bash マニュアルの「算術評価」セクションによると、算術式では次のようになります。

   Shell variables are allowed as  operands;  parameter  expansion  is  performed  before  the
   expression  is  evaluated.  Within an expression, shell variables may also be referenced by
   name without using the parameter expansion syntax.

では、この例で bash が を$nと異なる方法で処理するのはなぜでしょうかn。また、 は をどのように評価するのでしょうか$n


カンマ演算子を使用せずに問題を再現することはできませんでした。私がいつも見ているように、カンマ演算子は、各コンポーネントの計算時に各コンポーネントのすべての副作用を含め、各コンポーネントのサブ式を左から右に計算します。カンマ式の値は、最後に計算されたコンポーネント (右端のコンポーネント) の値になります。


この質問は、はるかに複雑なスクリプトのコンテキストで発生し、最終的に、問題を示すこの単純な例に絞り込みました。

では、算術展開、パラメータ展開、またはコンマ演算子について、私は何を誤解しているのでしょうか?

回避策を探しているのではないことに注意してください。すでに回避策があります。 のn代わりにを使用したバージョンは期待どおりに動作します。 を使用したバージョンで bash が何を実行しているのか、 のみのバージョンとは異なる動作をする理由$nを理解したいだけです。$nn

答え1

シェルパラメータの展開が発生する式が評価される前に、カンマの処理を含む:

式は二重引用符で囲まれているかのように扱われますが、括弧内の二重引用符は特別に扱われません。式内のすべてのトークンは、パラメータと変数の展開、コマンドの置換、および引用符の削除の対象になります。結果は、評価される算術式として扱われます。

これは次のように確認できます

unset n
echo $((n++,k=$n))

エラーメッセージ、

bash: n++,k=: syntax error: operand expected (error token is "=")

$n算術式全体が処理される前に置き換えられることを示します。

あなたの場合、評価される式は

n++,k=3

答え2

内部では$((...))、まず二重引用符で囲まれているかのように展開が行われ¹、その後結果が評価されます。

したがってn=3; k=10; echo $((n++,k=$n))、 (またはn=1; echo "$((++n + $n))"、 に限定されません,) では、評価される算術式は ですn++, k=3

ここで必要なもの:

n=3; k=10; echo "$((n++,k=n))"

(また、算術展開は POSIX シェルの他の形式の単語展開と同様に split+glob の対象となるため、引用符にも注意してください)。


¹、配列や連想配列が呼び出される場所にはいくつかのバリエーションがあります。これは$((hash[$key]++))、たとえば、$key]

関連情報