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?
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?
Jawaban:
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 -c 'echo {3..1}{c..a}'
dicetak 3{c..a} 2{c..a} 1{c..a}
di linux. Bukan "ekspansi brace" penuh.
{a..c}1 {a..c}2 {a..c}3
Perluasan brace di {a..c}{1..3}
diperluas dari kiri ke kanan, jadi Anda pertama mendapatkan a{1..3} b{1..3} c{1..3}
dan kemudian huruf digabungkan dengan angka-angka ke a1 a2 a3 b1 b2 b3 c1 c2 c3
. Untuk mendapatkan pesanan yang Anda inginkan, Anda harus menggunakan ekspresi yang sedikit lebih panjang di atas.
Menggunakan loop:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
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
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Ini tidak akan memberi Anda trailing newline tetapi jika Anda meneruskannya ke perintah atau variabel yang seharusnya tidak menjadi masalah.
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:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
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).
$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2
a1
b1
c1
a2
b2
c2
a3
b3
c3
Jika Anda menginginkannya dalam satu baris, Anda dapat menggunakan tr seperti:
$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2|tr '\n' ' '
a1 b1 c1 a2 b2 c2 a3 b3 c3
Dilakukan dengan metode di bawah ini
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
keluaran
a1 b1 c1 a2 b2 c2 a3 b3 c3 a4 b4 c4 a5 b5 c5 a6 b6 c6 a7 b7 c7 a8 b8 c8 a9 b9 c9 a10 b10 c10
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo
yash -o braceexpand
ke daftar.