Bash [[]] komutu içinde otomatik değişken genişletme


13

Bir değişkeni kayıttan çıkarırken bash, $işaretini kullanmanız gerekir . Bununla birlikte, aşağıdakilerin iyi çalıştığı görülüyor:

x=5
[[ x -gt 2 ]]

Bunu açıklayan var mı?

Düzenle: (daha fazla bilgi)

Demek istediğim, [[]] komutunun $ işaretini kullanmadan değişkenim x'in kayıtlarını nasıl ve neden kaldırdığıdır. Ve evet, x = 1 ise, ifade false olarak değerlendirilir (dönüş durumu 1)


2
"İyi çalışmak" ile ne demek istiyorsun? Eğer yoksa Ve değerlendirmeleriniz değişikliği yapar x=1izledi [[ x -gt 2]]?
nohillside

Demek istediğim: Nasıl ve neden [[]] komutu $ işaretini kullanmadan değişkenim x'in kayıtlarını siliyor. Ve evet, x = 1 ise, ifade yanlıştır (dönüş durumu 1)
Konuk

Yanıtlar:


9

Bunun nedeni, -eqgüçlerin argümanların aritmetik bir değerlendirmesidir.

Bir aritmetik operatörü: -eq, -gt, -lt, -ge, -leve -nebir iç [[ ]](ksh, zsh ve bash) otomatik c dilinde gibi değişken isimleri genişletmek için araçlar, lider için gerek $.

  • Onay için bash kaynak kodunu incelemeliyiz. Kılavuz doğrudan bir onay sunmamaktadır.

    İçinde test.caritmetik operatörlerin işlem bu işlevin ayrılır:

    arithcomp (s, t, op, flags)

    Nerede sve tikisi de işlenen. İşlenenler bu işleve teslim edilir:

    l = evalexp (s, &expok);
    r = evalexp (t, &expok);
    

    İşlev evalexp, expr.cbu başlığa sahip olan içinde tanımlanır :

    /* expr.c -- arithmetic expression evaluation. */

    Yani, evet, aritmetik bir operatörün her iki tarafı (doğrudan) aritmetik ifade değerlendirmesine girer. Doğrudan, iz yok, ifs yok.


Uygulamada:

 $ x=3

Her ikisi de başarısız:

 $ [[ x = 4 ]] && echo yes || echo no
 no

 $ [[ x = 3 ]] && echo yes || echo no
 no

Doğru olan, xgenişletilmiyor ve xbir sayıya eşit değil.

Ancak:

 $ [[ x -eq 3 ]] && echo yes || echo no
 yes

 $ [[ x -eq 4 ]] && echo yes || echo no
 no

Adlı değişken xgenişletilir ($ olmadan bile).

Bu, […]zsh veya bash için (ksh'da değil) gerçekleşmez.


Bu, a'nın içinde olanla aynıdır $((…)):

 $ echo $(( x + 7 ))
 10

Ve lütfen bunun (çok) özyinelemeli olduğunu (çizgi ve yaş hariç) anlayın:

 $ a=b b=c c=d d=e e=f f=3
 $ echo "$(( a + 7 ))" 
 10

A 😮

Ve oldukça riskli:

 $ x='a[$(date -u)]'
 $ [[ x -eq 3 ]] && echo yes || echo no
 bash: Tue Dec  3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec  3 23:18:19 UTC 2018")

Sözdizimi hatası kolayca önlenebilir:

 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

 $ [[ x -eq 3 ]] && echo yes || echo no
 Tue Dec  4 09:02:06 UTC 2018
 yes

Söyledikçe: girdinizi dezenfekte edin

 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
 no

😮 sonu


Hem (eski) harici /usr/bin/test(yerleşik değil test) hem de hala eski ve aynı zamanda harici ifadeler yalnızca tamsayıları (ve görünüşe göre yalnızca ondalık tamsayıları) exprgenişletmez :

 $ /usr/bin/test "x" -eq 3
 /usr/bin/test: invalid integer x

 $ expr x + 3
 expr: non-integer argument

İlginç. Bunun nasıl mümkün olduğunu söylemek zor değil - [[bir anahtar sözcük, işleçler ve işlenenler komut genişletildiğinde değil okunduğunda algılanıyor. Böylece [[tedavi edebilir -eq, diyelim ki, daha akıllı bir şekilde [. Ama merak ediyorum: Bileşik komutları yorumlamak için mantık bash'ın kullandığı belgeler nerede bulabilir? Benim için çok açık görünmüyor ve görünüşe göre manya da içinde tatmin edici açıklamalar bulamıyorum info bash.
fra-san

Bash bulabildiğim hiçbir yerde bunu belgelemiyor. Adam ksh93'te bir tür açıklama vardır : Aşağıdaki eski aritmetik karşılaştırmalara da izin verilir: exp1 -eq exp2 . Bu metin yoktur insanın zshbuiltins bölümünde aritmetik operatörler yerine aritmetik ifadelerden daha argümanlar tamsayı bekliyoruz . Bu, bazı bağımsız değişkenlerin test yerleşimi tarafından bu alıntıda belirtilmeyen koşullar altında aritmetik ifadeler olarak ele alındığını onaylar . Kaynak koduyla onaylayacağım….…test
NotAnUnixNazi

7

Sayısal karşılaştırmaların işlenenler -eq, -gt, -lt, -ge, -leve -nearitmetik ifadeler olarak alınır. Bazı sınırlamalarla, yine de tek kabuklu kelimeler olmaları gerekir.

Değişken adlarının aritmetik ifadedeki davranışı Kabuk Aritmetiği'nde açıklanmıştır :

Kabuk değişkenlerine işlenen olarak izin verilir; parametre genişletmesi, ifade değerlendirilmeden önce gerçekleştirilir. Bir ifade içinde, kabuk değişkenlerine parametre genişletme sözdizimi kullanılmadan ada göre de başvurulabilir. Null veya unset olan bir kabuk değişkeni, parametre genişletme sözdizimi kullanılmadan adıyla başvurulduğunda 0 olarak değerlendirilir.

ve ayrıca:

Değişkenin değeri, başvurulduğunda aritmetik bir ifade olarak değerlendirilir

Ancak, sayısal karşılaştırmaların aritmetik ifadeler aldığı söylenen belgelerin bir kısmını bulamıyorum. Bu tarif değil Şartlı Yapıtlarının altında [[, ne de açıklanan Bash Koşullu İfadeler .

Ancak, deney yoluyla, yukarıda belirtildiği gibi çalışıyor gibi görünüyor.

Yani, bunun gibi şeyler çalışır:

a=6
[[ a -eq 6 ]] && echo y 
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y

bu da (değişkenin değeri değerlendirilir):

b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y

Ama bu olmaz; [[ .. ]]ayrıştırıldığında tek bir kabuk sözcüğü değildir , bu nedenle koşulda bir sözdizimi hatası vardır:

[[ 1 + 2 + 3 -eq 6 ]] && echo y

Diğer aritmetik bağlamlarda, ifadenin boşluk olmadan olmasına gerek yoktur. 999Köşeli parantezler dizindeki aritmetik ifadeyi açıkça sınırladığı için bu yazdırılır :

a[6]=999; echo ${a[1 + 2 + 3]}

Öte yandan, =karşılaştırma bir kalıp eşleşmesidir ve aritmetik veya aritmetik bağlamda yapılan otomatik değişken genişleme (Koşullu Yapılar) içermez:

Ne zaman ==ve !=operatörler kullanılır extglob kabuk seçeneği etkin sanki, operatörün sağındaki dize, Kalıp Eşleme aşağıda açıklanan kurallara göre bir model olarak kabul edilir ve eşleştirilir. =Operatör ile aynıdır ==.

Dizeler açıkça farklı olduğu için bu yanlıştır:

[[ "1 + 2 + 3" = 6 ]] 

sayısal değerler aynı olmasına rağmen şu şekilde:

[[ 6 = 06 ]] 

ve burada da dizeler ( xve 6) karşılaştırılıyor, farklılar:

x=6
[[ x = 6 ]]

Bu, değişkeni genişletir, bu yüzden bu doğrudur:

x=6
[[ $x = 6 ]]

gerçekte sayısal karşılaştırmaların aritmetik ifadeler aldığı söylenen kısmı bulamıyor. Onaylama içindedir kodu .
NotAnUnixNazi

En yakın şey, açıklamasının arg1 OP arg2, argümanların aritmetik ifadeler olarak ele alındığını ima etmesi gereken sanırım pozitif veya negatif tamsayılar olabileceğini söylüyor. Kafa karıştırıcı bir şekilde, sıfır olamayacakları anlamına da gelir. :)
Barmar

@ Barmar, ehh, doğru. Ancak bu, sayısal karşılaştırmalar için [de geçerlidir ve orada aritmetik ifadeler yoktur. Bunun yerine, Bash tamsayı olmayanlardan şikayet eder.
ilkkachu

@ilkkachu [harici bir komuttur, kabuk değişkenlerine erişimi yoktur. Genellikle yerleşik bir komutla optimize edilir, ancak yine de aynı şekilde davranır.
Barmar

@Barmar, kastettiğim "Arg1 ve arg2 ifadelerinin pozitif veya negatif tamsayılar olabileceğiydi." içinde görünür Bash Koşullu İfadeler ve bu liste için geçerli [kadar iyi [[. [İle bile , işlenenler -eqve arkadaşlar tamsayı olmalıdır / olmalıdır, bu nedenle açıklama da geçerlidir. "Aritmetik ifadeler olarak yorumlanır" demek için "tamsayı olmalı" ifadesi almak her iki durumda da geçerli değildir. (Muhtemelen en azından kısmen [, söylediğiniz gibi sıradan bir komut gibi davranması nedeniyle ).
ilkkachu

1

Evet, gözleminiz doğrudur, çift parantez altındaki ifadelerde değişken genişleme gerçekleştirilir [[ ]], bu nedenle $değişken adının önüne koymanız gerekmez .

Bu bashkılavuzda açıkça belirtilmiştir :

[[ifade]]

(...) Kelime ayırma ve yol adı genişletme [[ve]] arasındaki sözcüklerde gerçekleştirilmez; dalga genişletme, parametre ve değişken genişletme, aritmetik genişletme, komut değiştirme, işlem değiştirme ve tırnak kaldırma gerçekleştirilir.

Bunun, bir kabuk anahtar kelimesi (sözdizimi) değil [ ], tek komutlu bir sürüm [değil, bir komut (bash'da yerleşik olarak, diğer kabuklar test etmek için dışlanmış, harici kullanılabilir) olduğuna dikkat edin.


1
Yanıtladığınız için teşekkürler. Bu sadece sayılar için çalışıyor gibi görünüyor. x = city [[$ x == city]] $ işareti olmadan çalışmaz.
Konuk

3
Burada daha fazlası var gibi görünüyor: (x=1; [[ $x = 1 ]]; echo $?)döndürür 0, (x=1; [[ x = 1 ]]; echo $?)döndürür 1, yani xdizeleri karşılaştırdığımızda parametre genişletme gerçekleştirilmez . Bu davranış, aritmetik genişleme tarafından tetiklenen aritmetik değerlendirmeye benziyor, yani ne oluyor (x=1; echo $((x+1))). (Aritmetik değerlendirme hakkında, man bash"Bir ifade içinde, kabuk değişkenlerine parametre genişletme sözdizimi kullanılmadan ada göre de atıfta bulunulabilir)"
fra-san

@ fra-san Gerçekten, -gtoperatör sayının tüm ifadenin içerideymiş gibi yeniden değerlendirilmesini beklediğinden (()), diğer yandan ==dizeleri bekler, böylece desen eşleştirme işlevi tetiklenir. Kaynak koduna girmedim ama kulağa mantıklı geliyor.
jimmij

[bash'ta bir kabuk yerleşmesidir.
Nizam Mohamed

1
@NizamMohamed Bir yerleşiktir, ancak yine de bir anahtar kelime değildir.
Kusalananda
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.