Bash'te iç içe geçmiş ayraç genişletme gizemi


19

Bu:

$ echo {{a..c},{1..3}}

bunu üretir:

a b c 1 2 3

Hangisi güzel, ama açıklaması zor

$ echo {a..c},{1..3}

verir

a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

Bu bir yerde belgelendi mi? Bash Referans (bunu kullanan bir örnek olsa bile) söz etmez.

Yanıtlar:


18

Her seferinde bir katman çözülüyor:

X{{a..c},{1..3}}Y

olarak genişletilmiş X{a..c}Y X{1..3}Y( varlık ve varlık ile X{A,B}Ygenişletilmiş ), kendileri de genişletilmiş olarak belgelenmiştir .XA XBA{a..c}B{1..3}XaY XbY XcY X1Y X2Y X3Y

Ne belgeleyen değerinde olabilir (ilk onlar iç içe olmasıdır }değildir yakın ilk {örneği için orada).

Sanırım mermiler ilk önce parantezleri çözmeyi seçmiş olabilir , mesela her kapanışa göre hareket ederek }:

  1. X{{a..c},{1..3}}
  2. X{a,{1..3}}Y X{b,{1..3}}Y X{c,{1..3}}Y

    (yani A{a..c}Bgenişletilmiş AaB AbB AcB, burada Aolduğu X{ve Bolduğu ,{1..3}Y)

  3. X{a,1}Y X{a,2}Y X{a,3}Y X{b,1}Y X{b,2}Y X{b,3}Y X{c,1}Y X{c,2}Y X{c,3}Y

  4. XaY X1Y XaY Xa2...

Ama özellikle daha sezgisel veya kullanışlı bulmuyorum (örneğin, Kevin'in yorumlardaki örneğine bakın), genişlemelerin hangi sırayla yapılacağı konusunda bazı belirsizlikler olacaktır ve bu böyle değildir csh(küme ayracı getiren kabuk 70'lerin sonunda genişlerken, {1..3}form daha sonra (1995) zshve {a..c}daha sonra (2004) geldi bash).

Not o csh(baştan bkz 2BSD (1979) kılavuz sayfasına ayracı açılımları iç içe olabilir aslında belgesini yaptım), gerçi açıkça genişletilecek nasıl iç içe ayracı açılımları demedi. Ancak 1979'daki koda, nasıl yapıldığını görmek için bakabilirsinizcsh . Gerçekten iç içe yerleştirmeyi nasıl işlediğini ve dış parantezlerden başlayarak nasıl çözüldüğünü görün.

Her durumda, genişlemenin nasıl {a..c},{1..3}bir etkisi olabileceğini gerçekten görmüyorum . Orada, ,küme ayracı genişlemesinin bir operatörü değildir (parantez içinde olmadığı için), bu nedenle herhangi bir sıradan karakter gibi ele alınır.


Dış parantezlerin içten önce çözülmesi gerektiği garip görünüyor.
Hauke ​​Laging

@ stéphane-chazelas Bu ifadenin ayrıştırılabilmesinin iki belirgin yolu vardır. Neden diğerine değil, bir yöne ayrıştırılıyor? Yorumunuz bir açıklama vermiyor.
igal

Yani, bu açıklama mantıklı, ama eğer bu "genişletilmiş olarak belgeleniyorsa ..." bir URL var mı?
xenoid

@xenoid Güncellenmiş çözümüme bakın.
Igal

1
@ (herkes): Genişlemeyi düşünün /dev/{h,s}d{a..d}{1..4,}. Şimdi varsayalım /dev/nullve bunu da içerecek şekilde genişletmek istiyorsunuz /dev/zero. Brace genişlemesi içten dışa işe yarasaydı, bu genişleme inşa etmek gerçekten sinir bozucu olurdu. Ancak dışarıdan çalıştığı için oldukça önemsiz:/dev/{null,zero,{h,s}d{a..d}{1..4,}}
Kevin

7

İşte kısa cevap. İlk ifadede virgül ayırıcı olarak kullanılır, bu nedenle küme ayracı genişlemesi sadece iç içe iki alt ifadenin birleşimidir. Ürün ifadeleri, ikinci ifadede virgül kendisi, tek bir karakter alt ifade olarak kabul edilir olan oluşturulur.

Eksik olan parantez açılımlarının nasıl yapıldığıdır. İşte üç referans:

Daha ayrıntılı bir açıklama aşağıdadır.


Bu ifadenin sonucunu karşılaştırdınız:

$ echo {{a..c},{1..3}}
a b c 1 2 3

bu ifadenin sonucuna:

$ echo {a..c},{1..3}
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

Bunun açıklanması zor, yani bunun sezgisel olduğunu söylüyorsunuz. Eksik olan, ayraç genişlemelerinin nasıl işlendiğinin resmi bir tanımıdır. Bash El Kitabının tam bir tanım sağlamadığını unutmayın .

Biraz aradım ama eksik (tam, resmi) tanımı da bulamadım. Bu yüzden kaynak koduna gittim:

Kaynak birkaç faydalı yorum içeriyor. Birincisi, küme ayracı genişletme algoritmasına üst düzey bir genel bakış:

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.

Dolayısıyla, küme ayracı genişletme belirtecinin biçimi şöyledir:

<PREAMBLE><AMBLE><POSTAMBLE>

Genişlemeye ana giriş noktası, brace_expandşu şekilde açıklanan bir işlevdir :

Return an array of strings; the brace expansion of TEXT.

Böylece brace_expandişlev, küme ayracı genişletme ifadesini temsil eden bir dize alır ve genişletilmiş dizelerin dizisini döndürür.

Bu iki gözlemin bir araya gelmesiyle, amble'in her biri giriş ekinde birleştirilen bir dizeler listesine genişletildiğini görüyoruz. Daha sonra postamble bir dize listesine genişletilir ve postamble listesindeki her dize, önsöz / amble listesindeki her bir dizeye birleştirilir (yani, iki listenin ürünü oluşturulur). Ancak bu, amble ve postamble'ın nasıl işlendiğini açıklamaz. Neyse ki bunu da açıklayan bir yorum var. Amble, expand_ambletanımının önünde aşağıdaki yorum olan bir işlev tarafından işlenir :

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.

Kodun başka bir yerinde BRACE_ARG_SEPARATOR'un virgül olarak tanımlandığını görüyoruz. Bu, amble'ın, bazıları da küme ayracı genişletme ifadeleri de olabilen virgülle ayrılmış bir dizeler listesi olduğunu açıkça ortaya koymaktadır. Bu dizeler daha sonra tek bir dizi oluşturur. Son olarak, biz de sonra görebilirsiniz expand_ambledenir brace_expandişlevi daha sonra postamble üzerinde ardışık olarak adlandırılır. Bu bize algoritmanın tam bir tanımını verir.

Bu bulguyu doğrulayan başka (gayri resmi) referanslar da vardır.

Bir referans için Bash Hackers Wiki'sine göz atın . Birleştirme ve yerleştirme bölümü sorununuzu tam olarak ele almıyor, ancak sayfa sorunuzu cevapladığını düşündüğüm söz dizimi genişlemesi sözdizimi / dilbilgisi veriyor. Sözdizimi aşağıdaki kalıplarla verilir:

{string1,string2,...,stringN}

{<START>..<END>}

<PREAMBLE>{........}

{........}<POSTSCRIPT>

<PREAMBLE>{........}<POSTSCRIPT>

Ayrıştırma şu şekilde açıklanır:

Brace genişletmesi rastgele dizeler oluşturmak için kullanılır. Belirtilen dizeler , isteğe bağlı çevreleyen önsözler ve postscriptler ile tüm olası kombinasyonları oluşturmak için kullanılır .

Başka bir referans için, aşağıdakileri içeren Bash Acemi Rehberine göz atın :

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.

Böylece küme ayracı genişleme ifadelerini ayrıştırmak için soldan sağa doğru gidip her bir ifadeyi genişletir ve birbirini takip eden ürünler oluştururuz (dizi-birleştirme işlemiyle ilgili olarak).

Şimdi ilk ifadenizi düşünelim:

{{a..c},{1..3}}

Bash Hacker'ın Wiki'sinde, bu ilk formla eşleşir:

{string1,string2,...,stringN}

Burada N=2, string1={a..c}ve string2={1..3}- iç bağ açılımları önce gerçekleştirilen ve her biri yapıdadır {<START>..<END>}. Alternatif olarak, bunun sadece bir amble (önsöz veya postamble içermeyen) içeren bir küme ayracı genişletme ifadesi olduğunu söyleyebiliriz. Amble, virgülle ayrılmış bir listedir, bu nedenle listeden birer birer yuvaya gider ve gerektiğinde ek genişletmeler yaparız. Hiçbir ürün oluşmaz, çünkü bitişik ifadeler yoktur (virgül ayırıcı olarak kullanılır).

Şimdi ikinci ifadenize bakalım:

{a..c},{1..3}

Bash Hacker'ın Wiki'sinde, bu ifade şu formla eşleşir:

{........}<POSTSCRIPT>

burada postscript alt ifadedir ,{1..3}. Alternatif olarak, bu ifadenin bir amble ( {a..c}) ve bir postamble ( ,{1..3}) olduğunu söyleyebiliriz . Amble, listeye genişletilir a b cve daha sonra bunların her biri, postamble'ın genişlemesindeki dizelerin her biri ile birleştirilir. Postamble özyinelemeli olarak işlenir: bir önsözü ,ve bir özü vardır {1..3}. Bu listeye genişletilir ,1 ,2 ,3. İki liste a b cve ,1 ,2 ,3daha sonra ürün listesini oluşturmak üzere birleştirilir a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3.

Bu ifadelerin nasıl ayrıştırıldığına dair psuedo-cebirsel bir açıklama vermek yardımcı olabilir, burada köşeli parantez "[]" dizileri gösterir, "+" dizi birleştirme anlamına gelir ve "*" Kartezyen ürünü (birleştirme ile ilgili olarak) belirtir.

İlk ifade şu şekilde genişletilir (satır başına bir adım):

{{a..c},{1..3}}
{a..c} + {1..3}
[a b c] + [1 2 3]
a b c 1 2 3

İkinci ifade şu şekilde genişletilir:

{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

2

Benim anlayışım şudur:

İç diş telleri önce çözülür (her zaman olduğu gibi)

{{a..c},{1..3}}

içine

{a,b,c,1,2,3}

Parantez ,içinde olduğu için sadece ayraç elemanlarını ayırır.

Ancak

{a..c},{1..3}

,ayraçları her iki tarafta da ayracı permütasyon neden sıradan bir karakterdir yani içinde değil.


Yani {a..c}ya giderir a,b,cveya a b cnem ve Dow Jones bağlı? Temiz.
kubanczyk

Bu biraz kafa karıştırıcı görünüyor. Eğer {{a..c},{1..3}}aynıdır {a,b,c,1,2,3}, o zaman olmamalıdır {{a..c}.{1..3}}aynı olacak {a,b,c.1,2,3}? Tabii ki durum böyle değil.
ilkkachu

@ilkkachu Bu neden aynı olmalı? ,küme ayracı genişleme ayırma karakteri, .değil. Sıradan bir karakter neden özel bir karakterle aynı sonuçlara yol açsın? c.1bir küme ayracı öğesidir. Ama içinde sol ve sağda ayracı açılımları için çapa olduğunu. İle dış parantez ayracı genişlemesi için kullanılmaktadır içerikleri ile, bağ genleşme biçimi vardır çünkü{a..c}.{1..3}.,. içeriklerinin bu biçimi olmadığı için onlar değil.
Hauke ​​Laging

@HaukeLaging, iyi, eğer {{a..c},{1..3}}içine dönüşler {a,b,c,1,2,3}sadece arasına göründü sonra bazı virgül a, bve c. Neden bununla aynı şekilde görünmezler {a..c}.{1..3}? @Kubanczyk'in yorumu aynı şeyle ilgilidir, virgüller orada böyle görünüyorsa, genişlemenin virgül ürettiğini ve ne zaman üretmediğini nasıl bilebiliriz? Cevap, hiçbir zaman virgül üretmemesi, bir kelime listesi oluşturmasıdır. Böylece hiçbir şey {a,b,c,1,2,3}veya haline dönüşmez {a,b,c.1,2,3}.
ilkkachu

@kubanczyk Anlamadığınız cevaplarla dalga geçmemelisiniz.
Hauke ​​Laging
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.