bashの{a、b、c}はいつ拡張され、いつ拡張されないのですか?

bashの{a、b、c}はいつ拡張され、いつ拡張されないのですか?

Bashスクリプトには以下が含まれています。

for i in {a,b}-{1,2}; do
  echo $i;
done

印刷

a-1
a-2
b-1
b-2

実行するとき。{a,b}構造が拡大するにつれて、これが私が期待するものです。

ただし、(他の)スクリプトに次のものが含まれている場合

v={a,b}-{1,2}
echo $v

それは印刷する

{a,b}-{1,2}

これは私が期待したものではありません。私はそれが印刷されると予想しましたa-1 a-2 b-1 b-2。もちろん、{a,b}構造は拡張されません。

このように拡張できます。

v=$(echo {a,b}-{1,2})

これらの観察に基づいて、2つの質問があります。 1){a,b}構成はいつ拡張されますか? 2)$(echo {a,b}-{1,2})必要に応じて拡張を実行するのに好ましい方法ですか?

答え1

これバッシュマニュアル説明する:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

中括弧の拡張はリストにないため、割り当てでは実行されませんv={a,b}-{1,2}。 @Wildcardが述べたように、単純な拡張はv=a-1 v=b-1 ...とにかく意味がありません。

また、を実行すると、echo $v次のことが適用されます。

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

中括弧拡張は変数拡張の前に発生するため、割り当てられた中括弧は$v拡張されません。

しかし、次のようにすることができます。

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

$(echo ...)拡張したい文字列にスペースが含まれていない場合、拡張機能は機能するため、単語分割の問題は発生しません。より良いアプローチは、可能であれば配列変数を使用することです。

たとえば、拡張を配列に保存し、拡張値を使用していくつかのコマンドを実行します。

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"

答え2

興味深い点。次の抜粋が役に立ちますman bash

変える次の形式のステートメントとして割り当てることができます。

      名前=[]

もし指定しない場合、変数に空の文字列が割り当てられます。みんな価値チルダ拡張、パラメータおよび変数拡張、コマンド置換、算術拡張、および引用符の削除を実行します(下記のEXPANSIONを参照)。

ガサイの拡張はリストに記載されていません。

しかし、これはまだ質問を残します。つまり、これは変数の割り当てであり、したがって中括弧拡張の影響を受けないことをシェルはどのように知ることができますか?あるいは、より正確には、中括弧拡張を処理する前にシェルが変数の割り当てを認識するように定義されるように、解析順序は明確でエンコードされた場所ですか? (これは明らかにbashこれがうまくいく方法ですが、これを説明する正確な文書行が見つかりませんでした。)

答え3

私が知っているのは、{a、b、c}は直接エコーされたとき、またはコマンドと共に使用されるときに拡張されます(例:mkdir〜/ {a、b、c})。ただし、変数に設定されている場合はEvaluateにする必要があります。それに答えるか、議論として使用する前に!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

「a」の後に「b」がアルファベット順に[az]、「1」の後に「2」が10進順に[0-9]なので、カンマ「代わりに二重ピリオド」..」を使用できます。

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

答え4

Bashで変数に代入しても式は拡張されません。

この小さなスクリプトの場合、xには次の代わり"*"に拡張が含まれます"*"

#!/bin/bash
x=*
echo "$x"

ただし、一部の値はrefに展開されます。 ilkkachuの答えは素晴らしいです。

評価すると式が拡張されます。

このように:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

または次のようになります。

x=*
echo $x            # <-- evaluation of $x

または次のようになります。

x=*
eval echo "$x"     # <-- evaluation of `echo *`

トリガ$()は非常に一般的で優れていると思いますeval。しかし、変数が実際にコマンドに使用されるまで、評価をまったくトリガーしないことが最善です。

関連情報