Inilah jawaban singkatnya. Dalam ekspresi pertama koma digunakan sebagai pemisah, jadi ekspansi brace hanyalah gabungan dari dua subekspresi bersarang. Dalam ekspresi kedua koma tersebut sendiri diperlakukan sebagai subexpression karakter tunggal, sehingga ekspresi produk yang terbentuk.
Apa yang Anda lewatkan adalah definisi tentang bagaimana brace-ekspansi dilakukan. Berikut adalah tiga referensi:
Penjelasan lebih rinci berikut.
Anda membandingkan hasil dari ungkapan ini:
$ echo {{a..c},{1..3}}
a b c 1 2 3
ke hasil ungkapan ini:
$ echo {a..c},{1..3}
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
Anda mengatakan bahwa ini sulit untuk dijelaskan, yaitu bahwa ini kontra-intuitif. Apa yang hilang adalah definisi formal tentang bagaimana brace-ekspansi diproses. Anda perhatikan bahwa Bash Manual tidak memberikan definisi penuh.
Saya mencari sedikit tetapi saya tidak dapat menemukan definisi yang hilang (lengkap, formal) juga. Jadi saya pergi ke kode sumber:
Sumber berisi beberapa komentar yang bermanfaat. Pertama adalah gambaran umum tingkat tinggi dari algoritma ekspansi brace:
Basic idea:
Segregate the text into 3 sections: preamble (stuff before an open brace),
postamble (stuff after the matching close brace) and amble (stuff after
preamble, and before postamble). Expand amble, and then tack on the
expansions to preamble. Expand postamble, and tack on the expansions to
the result so far.
Jadi format token ekspansi-ekspansi adalah sebagai berikut:
<PREAMBLE><AMBLE><POSTAMBLE>
Titik masuk utama ke ekspansi adalah fungsi yang disebut brace_expand
yang dijelaskan sebagai berikut:
Return an array of strings; the brace expansion of TEXT.
Jadi brace_expand
fungsi mengambil string yang mewakili ekspresi ekspansi penjepit dan mengembalikan array string yang diperluas.
Menggabungkan dua pengamatan ini kita melihat bahwa amble diperluas ke daftar string, yang masing-masing digabungkan ke pembukaan. Pembukaan pos kemudian diperluas ke daftar string, dan setiap string dalam daftar postamble digabungkan ke setiap string dalam daftar pembukaan / amble (yaitu produk dari dua daftar dibentuk). Tetapi ini tidak menjelaskan bagaimana amble dan postamble diproses. Untungnya ada komentar yang menggambarkan hal itu juga. Amble diproses oleh fungsi yang disebut expand_amble
definisi yang didahului oleh komentar berikut:
Expand the text found inside of braces. We simply try to split the
text at BRACE_ARG_SEPARATORs into separate strings. We then brace
expand each slot which needs it, until there are no more slots which
need it.
Di tempat lain dalam kode kita melihat bahwa BRACE_ARG_SEPARATOR didefinisikan sebagai koma. Ini memperjelas bahwa amble adalah daftar string yang dipisahkan koma, beberapa di antaranya mungkin juga merupakan ekspresi brace-expansion. String ini kemudian membentuk satu array. Akhirnya, kita juga bisa melihat bahwa setelah expand_amble
dipanggil brace_expand
fungsi kemudian dipanggil secara rekursif pada postamble. Ini memberi kita deskripsi lengkap tentang algoritma.
Ada beberapa referensi (tidak resmi) lain yang menguatkan temuan ini.
Untuk satu referensi, lihat Bash Hackers Wiki . Bagian tentang menggabungkan dan bersarang tidak cukup mengatasi masalah Anda, tetapi halaman tersebut memberikan sintaksis / tata bahasa dari ekspansi brace, yang menurut saya menjawab pertanyaan Anda. Sintaks diberikan oleh pola-pola berikut:
{string1,string2,...,stringN}
{<START>..<END>}
<PREAMBLE>{........}
{........}<POSTSCRIPT>
<PREAMBLE>{........}<POSTSCRIPT>
Dan penguraian dijelaskan sebagai berikut:
Ekspansi Brace digunakan untuk menghasilkan string acak. String yang ditentukan digunakan untuk menghasilkan semua kombinasi yang mungkin dengan preamble dan postscript opsional.
Untuk referensi lain, lihat Panduan Pemula Bash , yang memiliki kata-kata berikut ini:
Brace expansion is a mechanism by which arbitrary strings may be generated. Patterns to be brace-expanded take the form of an optional PREAMBLE, followed by a series of comma-separated strings between a pair of braces, followed by an optional POSTSCRIPT. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.
Jadi untuk mengurai ekspresi brace-expansion, kita belok kiri-ke-kanan, memperluas setiap ekspresi dan membentuk produk yang berurutan (berkenaan dengan operasi string-concatenation).
Sekarang mari kita perhatikan ungkapan pertama Anda:
{{a..c},{1..3}}
Dalam bahasa Wiki Hacker Bash, ini cocok dengan bentuk pertama:
{string1,string2,...,stringN}
Di mana N=2
, string1={a..c}
dan string2={1..3}
- ekspansi penjepit di dalam dilakukan pertama kali dan masing-masing dari mereka dalam bentuk {<START>..<END>}
. Sebagai alternatif, kita dapat mengatakan bahwa ini adalah ekspresi brace-expansion yang hanya terdiri dari amble (tidak ada pembukaan atau postamble). Amble adalah daftar yang dipisahkan koma, jadi kami memeriksa slot satu demi satu, dan melakukan ekspansi tambahan jika diperlukan. Tidak ada produk yang terbentuk karena tidak ada ekspresi yang berdekatan (koma digunakan sebagai pemisah).
Selanjutnya mari kita lihat ekspresi kedua Anda:
{a..c},{1..3}
Dalam bahasa Wiki Bash Hacker, ungkapan ini cocok dengan bentuk:
{........}<POSTSCRIPT>
di mana postscript adalah sub-ekspresi ,{1..3}
. Atau, kita dapat mengatakan bahwa ungkapan ini memiliki amble ( {a..c}
) dan postamble ( ,{1..3}
). Amble diperluas ke daftar a b c
dan kemudian masing-masing digabungkan dengan masing-masing string dalam ekspansi postamble. Pembukaan pos diproses secara rekursif: memiliki pembukaan ,
dan amble dari {1..3}
. Ini diperluas ke daftar ,1 ,2 ,3
. Dua daftar a b c
dan ,1 ,2 ,3
kemudian digabungkan untuk membentuk daftar produk a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
.
Mungkin membantu untuk memberikan deskripsi psuedo-aljabar tentang bagaimana ekspresi ini diuraikan, di mana tanda kurung "[]" menunjukkan array, "+" menunjukkan penggabungan array, dan "*" menunjukkan produk Cartesian (berkenaan dengan penggabungan).
Inilah cara ekspresi pertama diperluas (satu langkah per baris):
{{a..c},{1..3}}
{a..c} + {1..3}
[a b c] + [1 2 3]
a b c 1 2 3
Dan inilah cara ekspresi kedua diperluas:
{a..c},{1..3}
{a..c} * ,{1..3}
[a b c] * [,1 ,2 ,3]
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3