Misalnya {a..c}{1..3}
diperluas ke a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Jika saya ingin mencetak a1 b1 c1 a2 b2 c2 a3 b3 c3
, apakah ada cara analog untuk melakukannya? Apa cara paling sederhana?
sumber
Misalnya {a..c}{1..3}
diperluas ke a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Jika saya ingin mencetak a1 b1 c1 a2 b2 c2 a3 b3 c3
, apakah ada cara analog untuk melakukannya? Apa cara paling sederhana?
Anda bisa melakukannya:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Yang kemudian memberitahu shell untuk mengevaluasi:
echo {a..c}1 {a..c}2 {a..c}3
Untuk kasus khusus ini, saya pikir opsi yang diberikan oleh Stéphane Chazelas adalah yang terbaik.
Di sisi lain, ketika Anda memperluas hal-hal yang lebih kompleks, opsi ini tidak dapat diukur dengan baik. Jadi, Anda dapat mencapai hal yang sama dengan ini:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
yang mengembalikan:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Tampaknya sedikit berantakan, tetapi sekarang, saya memiliki kontrol besar dalam pesanan, hanya mengubah dua karakter pada perintah di atas; sebagai contoh:
$ echo {a..b}{1..2}{a..b}{1..2}
ini akan diperluas ke:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Misalkan saya ingin semua 1
dalam ekspansi kedua, maka 2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.2 | tr '\0' ' '
a1a1 a1a2 a1b1 a1b2 b1a1 b1a2 b1b1 b1b2 a2a1 a2a2 a2b1 a2b2 b2a1 b2a2 b2b1 b2b2
Misalkan saya ingin semua a
ekspansi ketiga, maka b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.3,1.3 | tr '\0' ' '
a1a1 a1a2 a2a1 a2a2 b1a1 b1a2 b2a1 b2a2 a1b1 a1b2 a2b1 a2b2 b1b1 b1b2 b2b1 b2b2
Misalkan saya ingin semua 1
dalam ekspansi keempat, maka 2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.4,1.4 | tr '\0' ' '
a1a1 a1b1 a2a1 a2b1 b1a1 b1b1 b2a1 b2b1 a1a2 a1b2 a2a2 a2b2 b1a2 b1b2 b2a2 b2b2
Misalkan saya ingin semua 1a
di tengah, lalu 1b
, lalu 2a
, kemudian 2b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.3 | tr '\0' ' '
a1a1 a1a2 b1a1 b1a2 a1b1 a1b2 b1b1 b1b2 a2a1 a2a2 b2a1 b2a2 a2b1 a2b2 b2b1 b2b2
Anda bahkan dapat, dengan mudah, membalik urutan apa pun dalam ekspansi di atas, hanya menambahkan r
perintah sebelumnya; misalnya, yang terakhir:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -rzk 1.2,1.3 | tr '\0' ' '
b2b2 b2b1 a2b2 a2b1 b2a2 b2a1 a2a2 a2a1 b1b2 b1b1 a1b2 a1b1 b1a2 b1a1 a1a2 a1a1
Note_1 : biasanya, jika ekspansi akhir ini akan digunakan sebagai daftar argumen, ruang tambahan tidak menjadi masalah; tetapi jika Anda ingin menghilangkannya, Anda dapat menambahkan, ke salah satu perintah di atas, misalnya| sed 's/ $//'
; atau bahkan| sed 's/ $/\n/'
, untuk mengubah ruang tambahan itu untuk anewline
Note_2 : Dalam contoh di atas, saya telah menggunakan himpunan bagian dari dua elemen (yaitu: {a, b} dan {1,2} ) hanya untuk kesederhanaan dalam bukti konsep: Anda dapat menggunakan himpunan bagian dari panjang yang terbatas, dan perintah yang sesuai, akan sebanding.
Liner satu yang bekerja di (bash, ksh, zsh) (tidak semua shell dapat melakukan "ekspansi Brace" dalam urutan terbalik):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Alternatif yang digunakan eval
(yang masih untuk bash, ksh, zsh dan mungkin lebih samar) adalah:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Untuk memahami apa yang terjadi, gantikan eval
denganecho
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Perintah dieksekusi (setelah ekspansi eval) sebenarnya echo {a..c}1 {a..c}2 {a..c}3
. Yang mengembang sesuai keinginan / kebutuhan.
Ada beberapa shell tanpa "brace expansions", jadi, tidak mungkin menggunakannya untuk "semua shell". Kami membutuhkan sebuah loop (dengan spasi spasi tambahan):
$ for i in 1 2 3; do for j in a b c; do printf "%s%s " "$j" "$i"; done; done; echo
a1 b1 c1 a2 b2 c2 a3 b3 c3
Jika Anda tidak boleh menambahkan spasi tambahan:
s=""
for i in 1 2 3; do
for j in a b c; do
printf "%s%s%s" "$s" "$j" "$i"
s=" "
done
done
echo
Cetakan
a1 b1 c1 a2 b2 c2 a3 b3 c3
JIKA Anda perlu melakukan ini untuk banyak nilai kita perlu menggunakan sesuatu yang mirip dengan ekspansi penjepit untuk menghasilkan daftar angka $(seq 10)
. Dan, karena seq tidak dapat menghasilkan daftar huruf, kita perlu mengonversi ke ascii angka yang dihasilkan:
s=""
for i in $(seq 4); do
for j in $(seq 5); do
printf "%s\\$(printf %03o $((96+j)))%s" "$s" "$i"
s=" "
done
done
echo
cetakan:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
yash -o braceexpand
ke daftar.yash -o braceexpand -c 'echo {3..1}{c..a}'
dicetak3{c..a} 2{c..a} 1{c..a}
di linux. Bukan "ekspansi brace" penuh.Perluasan brace di
{a..c}{1..3}
diperluas dari kiri ke kanan, jadi Anda pertama mendapatkana{1..3} b{1..3} c{1..3}
dan kemudian huruf digabungkan dengan angka-angka kea1 a2 a3 b1 b2 b3 c1 c2 c3
. Untuk mendapatkan pesanan yang Anda inginkan, Anda harus menggunakan ekspresi yang sedikit lebih panjang di atas.sumber
Menggunakan loop:
Ini akan mengulang melalui ekspansi pertama Anda dan kemudian memperluas setiap karakter dengan yang kedua.
Jika Anda membutuhkan output semua dalam satu baris, Anda dapat menghapus
\n
:Ini tidak akan memberi Anda trailing newline tetapi jika Anda meneruskannya ke perintah atau variabel yang seharusnya tidak menjadi masalah.
sumber
Ini berfungsi untuk kasing Anda yang sederhana dan dapat diperpanjang, tetapi akan cepat hilang kendali. Kasus-kasus yang lebih kompleks yang tidak bisa digunakan untuk membuatnya mudah dibuat.
Membalik urutan ekspansi brace, lalu menukar karakter:
sumber
Salah satu metode sederhana adalah dengan menggunakan sort (1.2.1.2 berarti Anda mengambil satu karakter di posisi kedua dan berakhir di tempat yang sama).
Jika Anda menginginkannya dalam satu baris, Anda dapat menggunakan tr seperti:
sumber
Dilakukan dengan metode di bawah ini
keluaran
sumber
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo