Braket genleşmesini "ters sırayla" uygulayın


21

Örneğin, {a..c}{1..3}genişler a1 a2 a3 b1 b2 b3 c1 c2 c3.

Basmak istesem a1 b1 c1 a2 b2 c2 a3 b3 c3, bunu yapmanın benzer bir yolu var mı? En basit yol nedir?

Yanıtlar:


30

Yapabilirsin:

$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3

Hangi kabuktan değerlendirmek için söyler:

echo {a..c}1 {a..c}2 {a..c}3

10

Bu özel durum için, Stéphane Chazelas'ın verdiği seçeneğin en iyisi olduğunu düşünüyorum .

Öte yandan, daha karmaşık şeyleri genişlettiğinizde, bu seçenek iyi ölçeklenemez. Böylece, bununla aynı şeyi başarabilirsiniz:

$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '

hangi döner:

a1 b1 c1 a2 b2 c2 a3 b3 c3

Biraz dağınık görünüyor, ama şimdi, sıradaki büyük kontrolüm var, sadece yukarıdaki komuttaki iki karakteri değiştiriyorum; Örneğin:

$ echo {a..b}{1..2}{a..b}{1..2}

bu, aşağıdakilere genişleyecektir:

a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2

Sanırım hepsini 1ikinci genişlemede istiyorum, sonra 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

Diyelim ki aüçüncü genişlemede hepsini istiyorum , sonra 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

1Dördüncü genişlemede hepsini istiyorum , sonra 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

Diyelim ki hepsini 1aortada istiyorum , sonra 1b, sonra 2a, sonra 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

Yukarıdaki açılımlardaki herhangi bir sırayı, kolayca rönceki komutunuza ekleyerek kolayca geri alabilirsiniz ; örneğin, sonuncusu:

$ 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

Not_1 : genellikle, bu son genişleme bir argüman listesi olarak kullanılacaksa, sondaki boşluk sorun olmaz; ama ondan kurtulmak istiyorsan, yukarıdaki komutlardan herhangi birine ekleyebilirsin, örneğin| sed 's/ $//' ; hatta| sed 's/ $/\n/', bu sondaki alanı değiştirmeknewline

Not_2 : Yukarıdaki örneklerde, kavramın ispatındaki basitlik içiniki öğenin alt kümelerini kullanıyorum (yani: {a, b} ve {1,2} ): Herhangi bir sonlu uzunlukta alt kümeleri kullanabilirsiniz karşılık gelen komut, karşılaştırılabilir olurdu.


5

bash, ksh, zsh

İçinde çalışan bir astar (bash, ksh, zsh) (tüm kabukları ters sırayla "Destek genişletme" yapamaz):

$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3

eval(Hala bash, ksh, zsh ve daha şifreli olabilir) kullanımına alternatif :

$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3

Yerine ne olacağını anlamak için evalbirlikte echo:

$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3

Yürütülen komut (eval genişlemesinden sonra) aslında echo {a..c}1 {a..c}2 {a..c}3. İstediğiniz / ihtiyaç duyduğunuz kadar genişler.

tüm kabukları

"Ayraç genişlemesi" olmayan birkaç mermi vardır, bu yüzden "tüm mermiler" için kullanmak mümkün değildir. Bir döngüye ihtiyacımız var (takip eden beyaz boşlukla):

$ 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 

Eklenen bir boşluk bırakmamış olmanız gerekiyorsa:

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

Baskılar

a1 b1 c1 a2 b2 c2 a3 b3 c3

Bunu birçok değer için yapmanız gerekiyorsa, bir sayı listesi oluşturmak için ayraç genişletmesine benzer bir şey kullanmamız gerekir $(seq 10). Sıra, bir harf listesi oluşturamadığından, üretilen sayıları ascii'ye dönüştürmemiz gerekir:

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

baskılar:

a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4

Ayrıca yash -o braceexpandlisteye ekleyebilirsiniz .
Stéphane Chazelas

@ StéphaneChazelas Yapmam gerektiğinden emin değilim. Komut linux dilinde yash -o braceexpand -c 'echo {3..1}{c..a}'basılıyor 3{c..a} 2{c..a} 1{c..a}. Tam bir "ayraç genişletme" değil.
Isaac,

3
{a..c}1 {a..c}2 {a..c}3

Parantez açılımları {a..c}{1..3}soldan sağa doğru genişler, böylece önce siz alırsınız a{1..3} b{1..3} c{1..3}, sonra harfler sayılarla birleştirilir a1 a2 a3 b1 b2 b3 c1 c2 c3. İstediğiniz sırayı almak için yukarıdaki biraz daha uzun ifadeyi kullanmanız gerekir.


Çok çeşitli "sayılar" için yapmak isteseydiniz artık pratik olmazdı.
RUBEN GONÇALO MOROUÇO

3
@ RUBENGONÇALOMOROUÇO Hayır olmaz ve eğer çok sayıda sayı için yapıyorsanız, çift döngü gibi alternatif bir yaklaşım kullanmanızı öneririm. Bu binlerce kombinasyon için işe yarar, ancak bir ayraç genişlemesi bazı bağlamlarda tetikleyici "tartışma listesi çok uzun" olur.
Kusalananda

2

Bir döngü kullanarak:

for n in {1..3}; do printf '%s\n' {a..c}"$n"; done

Bu, ilk genişletme işleminizi gerçekleştirecek ve ardından her karakteri ikinci ile genişletecektir.

Çıktıya tek bir satırda ihtiyacınız varsa, şunları kaldırabilirsiniz \n:

for n in {1..3}; do printf '%s ' {a..c}"$n"; done

Bu size sonda bir yeni hat vermeyecek, ancak eğer bir sorun olmamalı bir komuta veya değişkene geçiyorsanız.


1
Neden bir döngü çözümü için bu kadar çok aşağı oy?
Isaac,

Duh, soruyu yanlış okumuş olmalıyım. Güncelleme
Jesse_b

2

Bu, basit durum için işe yarar ve uzatılabilir, ancak hızlı bir şekilde elden çıkar. Bunun işe yaramayacağı daha karmaşık durumlarda yapılması kolaydır.

Ayraç genişlemelerinin sırasını ters çevirin, ardından karakterleri değiştirin:

echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'

@muru: Oops. Sabit. Teşekkürler.
sonraki duyuruya kadar duraklatıldı.

@Iacac: Sondaki boşluğu düzelttim.
sonraki duyuruya kadar duraklatıldı.

0

Basit bir yöntem, sıralama kullanmak olacaktır (1.2,1.2, ikinci bir karakterden birini aldığınız ve aynı yerde bittiğiniz anlamına gelir).

$ 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

Onları bir satırda istiyorsanız, tr gibi kullanabilirsiniz:

$ 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

-2

Aşağıdaki yöntemle yapılır

for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"

çıktı

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

ayrıca düşününfor i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo
Jeff Schaller
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.