{A, b, c} bash içinde ne zaman genişletilir, ne zaman değildir?


13

İçeren bir bash betiği

for i in {a,b}-{1,2}; do
  echo $i;
done

baskılar

a-1
a-2
b-1
b-2

yürütüldüğünde. Beklediğim bu - {a,b}yapı genişledikçe.

Ancak, (başka) bir komut dosyası içerdiğinde

v={a,b}-{1,2}
echo $v

yazdırır

{a,b}-{1,2}

beklediğim gibi değil. Yazdırmasını bekliyordum a-1 a-2 b-1 b-2. Açıkçası, {a,b}yapı genişletilmemiştir.

Bu şekilde genişleyebilirim

v=$(echo {a,b}-{1,2})

Bu gözlemlere dayanarak iki sorum var: 1) {a,b}yapı ne zaman genişletilir? 2) $(echo {a,b}-{1,2})gerektiğinde bir genişlemeyi tetiklemenin tercih edilen yolu nedir?


1
Bu en azından basit bir dizi değişkeni yapamamanızla tutarlıdır =. Örneğin, v=a-1 a-2çalışmaz.
grochmal

@grochmal - bunun nedeni skaler bir değer atamanızdır. v=a-1 a-2aracı assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)değişkenine dizisini atar v. v+=(b-1 b-2)ekler.
cas

Yanıtlar:


15

Bash manuel söylüyor:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

Köşeli ayraç genişletmesi listede değil, bu nedenle ödev için gerçekleştirilmez v={a,b}-{1,2}. @Wildcard tarafından belirtildiği gibi, basit genişleme v=a-1 v=b-1 ...zaten anlamsız olacaktır.

Ayrıca, çalıştırılırken echo $vaşağıdakiler geçerlidir:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

Brace genişlemesi değişken genişlemeden önce gerçekleşir, bu nedenle atanan parantezler $vgenişletilmez.

Ama böyle şeyler yapabilirsiniz:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

Genişletilecek $(echo ...)dizede herhangi bir boşluk yoksa ve bu nedenle sözcük bölme ile ilgili sorunlarla karşılaşmazsanız, genişletmek işe yaramalıdır. Mümkünse bir dizi değişkeni kullanmak daha iyi bir yol olabilir.

örneğin, genişletmeyi bir diziye kaydedin ve genişletilmiş değerlerle bir komut çalıştırın:

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"

5

İlginç bir nokta. Muhtemelen yararlı olan aşağıdaki alıntıdır man bash:

Bir değişken , formun ifadesiyle atanabilir

      name = [ değer ]

Eğer değer verilmediği, değişken boş dize atanır. Tüm değerler tilde genişletme, parametre ve değişken genişletme, komut değiştirme, aritmetik genişletme ve tırnak kaldırma işleminden geçer (aşağıdaki GENLEŞME'ye bakın).

Brace genişletmesinin listede belirtilmediğine dikkat edin.

Bununla birlikte, bu hala bir soru bırakıyor: Kabuk bunun değişken bir atama olduğunu ve dolayısıyla genişlemenin desteklenmediğini nasıl biliyor? Veya daha kesin olarak, ayrıştırma dizisi, kabuğun küme ayracı genişlemesini işlemeden önce değişken atamaları tanımlamak üzere tanımlanacağı şekilde nerede açıklığa kavuşturulur ve kodlanır? (Açıkçası bu nasıl bashçalışır, ancak bunu açıklayan tam bir belge satırı bulamadım.)


1
Belki bu ? "2. Değişken atamaları veya yeniden yönlendirmeleri olmayan kelimeler genişletilir (bkz. Kabuk Genişletmeleri)."
Jeff Schaller

@JeffSchaller, haklısın. Aslında bu soru en iyi şekilde sadece "BASİT KOMUT GENİŞLEME" ( LESS=+/SIMPLE man bash) bölümünü okuyarak cevaplanır .
Wildcard

0

lil bilgisine göre, {a, b, c} doğrudan yankılanırken veya bir komutla kullanıldığında genişletilir, örneğin: mkdir ~ / {a, b, c}, ancak bir değişkene ayarlandığında daha önce değerlendirilmelidir yankılanıyor ya da tartışma olarak kullanılıyor!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

alfa düzeninde [a] ve ardından “b” ve ara sıradaki [0-9] içinde “1” ve ardından “2” olduğu için: çift nokta ".." virgül aşılama "kullanabilirsiniz, "

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

1
Soru neden olduğu vdeğildi set hazır bilgi dizesi "a-1 a-2 b-1 b-2" olarak ayarlayın. Ya da en azından komutu v=a-1 v=a-2 v=b-1 v=b-2yazdığınızda neden hiçbir hata atılmadı: (bu değişken atamasının genişletilmesini beklersiniz). Bu iyi bir soru; bu gerçekten cevap vermiyor.
Wildcard

@SatoKatsura, "joker karakter genişletmesi" ne anlama geliyor? Parametre genişletmesi, yol adı genişletmesi ve küme ayracı genişletmesi vardır - bunlardan herhangi biri başvurabileceğiniz ve hepsi farklıdır. Yoksa kelime yarma mı demek istediniz?
Wildcard

0

Bash içinde bir değişkene atamak ifadeyi genişletmez.

Bu küçük komut dosyası için x aşağıdakileri içerecek "*"ve genişletmeyecektir "*":

#!/bin/bash
x=*
echo "$x"

Ancak, bazı değerler genişletilir, ref. ilkkachu'dan güzel cevap.

İfadeler değerlendirildiğinde genişletilir.

Bunun gibi:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

Veya bunun gibi:

x=*
echo $x            # <-- evaluation of $x

Veya bunun gibi:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

Tetikleme $()oldukça yaygındır ve bence tercih edilir eval, ancak en iyisi, değişken aslında bir komutta kullanılıncaya kadar muhtemelen değerlendirmeyi tetiklemektir.

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.