Bash operatörleri arasındaki fark nedir [[vs [vs (vs (??)


245

Bu operatörlerin bash'te (parantez, çift parantez, parantez ve çift parantez) kullanıldığında farklı şekilde yaptıkları konusunda biraz kafam karıştı.

[[ , [ , ( , ((

Ben böyle ifadeler insanların kullandığını gördüm:

if [[condition]]

if [condition]

if ((condition))

if (condition)

4
Önce unix.stackexchange.com/questions/tagged/test adresinden önce bakmak isteyebilirsiniz
cuonglm


3
@cuonglm İronik çünkü bu bağlantı bu soruyu ilk sonuç olarak veriyor . Paradox!
Insane

5
Sanırım belgeleri okumak bir seçenek değil mi?
Orbit'teki Hafiflik Yarışları

34
Parantez ve parantez belgelerde arama yapmak o kadar kolay değildir ve bu özelliklerin adlarını bilmiyorsanız elinizde kalan tek şey budur.
ilkkachu

Yanıtlar:


257

Bir ififade genellikle benziyor

if commands1
then
   commands2
else
   commands3
fi

thenÇıkış kodu ise bloğu icra edilir commands1sıfırdır. Çıkış kodu sıfır değilse, elsefıkra yürütülür. commands1basit veya karmaşık olabilir. Bu, örneğin, operatör tarafından ayrılan bir veya daha fazla boru hattı bir dizi olabilir ;, &, &&ya da ||. ifAşağıda gösterilen durumlar sadece özel durumlardır commands1:

  1. if [ condition ]

    Bu geleneksel kabuk testkomutudur. Tüm POSIX mermilerinde mevcuttur. Test komutu bir çıkış kodu belirler ve ififade buna göre davranır. Tipik testler, bir dosyanın var olup olmadığı veya bir sayının diğerine eşit olup olmadığıdır.

  2. if [[ condition ]]

    Bu yeni yükseltilen varyasyon testgelen ksh bash ve zsh da destekler. Bu testkomut aynı zamanda bir çıkış kodu belirler ve ififade buna göre davranır. Genişletilmiş özellikleri arasında bir dizgenin normal bir ifadeyle eşleşip eşleşmediğini test edebilir.

  3. if ((condition))

    Bash ve zsh'nin de desteklediği bir başka ksh uzantısı . Bu aritmetik gerçekleştirir. Aritmetik işlemin sonucu olarak, bir çıkış kodu belirlenir ve ifade buna göre davranır. Aritmetik hesaplamanın sonucu sıfır değilse, bir çıkış kodu sıfır (doğru) döndürür. Gibi , bu form POSIX değildir ve bu nedenle taşınabilir değildir.if[[...]]

  4. if (command)

    Bu, bir alt kabukta komutu çalıştırır. Komut tamamlandığında, bir çıkış kodu belirler ve ififade buna göre davranır.

    Bunun gibi bir alt kabuk kullanmanın tipik bir nedeni, commandgerekirse commanddeğişken atamalarının veya kabuğun ortamındaki diğer değişikliklerin yan etkilerini sınırlandırmaktır . Bu değişiklikler, alt kabuk tamamlandıktan sonra kalmaz.

  5. if command

    komut yürütülür ve ififade, çıkış koduna göre hareket eder.


24
5. seçeneği de dahil ettiğiniz için teşekkür ederiz. Bunun gerçekten nasıl çalıştığını ve şaşırtıcı şekilde yeterince kullanılmadığını anlamanın anahtarı budur.
civcivler

4
Bunun [aslında bir ikili olduğuna dikkat edin , dahili bir komut veya sembol değil. Genellikle içinde yaşar /bin.
Julien R.

8
@JulienR. aslında [olduğu gibi bir yerleşiktir test. Uyumluluk nedenlerinden dolayı ikili versiyonlar mevcuttur. Check out help [ve help test.
Oldtimer

4
Olmasına dikkat etmek gerekir ((değil POSIX, $((yani aritmetik genişleme ve onları karıştırmak kolaydır. Genellikle bir geçici çözüm, [ $((2+2)) -eq 4 ]koşullu ifadelerde aritmetik kullanmak gibi bir şey kullanmaktır)
Sergiy Kolodyazhnyy

1
Keşke bu cevabı bir kereden fazla oy kullanabilseydim. Mükemmel açıklama
Anthony Gatlin

77
  • (…)Parantezler alt kabuğu gösterir . İçlerinde olanlar, diğer birçok dilde olduğu gibi bir ifade değildir. Bu bir komut listesidir (tıpkı parantez içindeki gibi). Bu komutlar ayrı bir alt işlemde yürütülür, böylece parantez içinde yapılan herhangi bir yeniden yönlendirme, atama vb. Parantezlerin dışında bir etkiye sahip değildir.
    • Önde gelen dolar işaretiyle $(…)bir komut ikamedir : parantez içinde bir komut vardır ve komutun çıktısı komut satırının bir parçası olarak kullanılır (değiştirme çift tırnak işaretleri arasında olmadığı sürece fazladan genişlemelerin ardından, ancak bu başka bir hikaye ) .
  • { … }kaşlı ayraçlar, grup komutları içinde parantez gibidir; ancak yalnızca ayrıştırmayı etkiler, gruplamayı değil. Program x=2; { x=4; }; echo $xoysa baskılar 4, x=2; (x=4); echo $xbaskılar 2. (Ayrıca olma parantezi anahtar ayrılmış ve (komut konumunda bulunan dolayısıyla uzay sonra gereken {ve ;daha önce }. Parantezler yok olurken) Bu sadece bir sözdizimi cilvesi bu.)
    • Önde gelen dolar işaretiyle, olası ekstra dönüşümlerle bir değişkenin değerine genişleyen ${VAR}bir parametre genişletmesidir . ksh93Kabuk da destekleyen ${ cmd;}bir altkabuk çalıştırmak etmez komut ikamesi şekli olarak.
  • ((…))çift ​​parantezler , diğer programlama dillerine benzeyen bir sözdizimi ile, bir tamsayıdaki hesaplama olan aritmetik bir talimatı çevreler . Bu sözdizimi çoğunlukla ödevler ve şartlar için kullanılır. Bu, sadece sh 'de değil, ksh / bash / zsh’da bulunur.
    • Aynı sözdizimi, ifadenin $((…))tamsayı değerine genişleyen aritmetik ifadelerde kullanılır .
  • [ … ]tek parantez koşullu ifadeleri çevreliyor . Koşullu ifadeler, değişkenlerin boş olup olmadığını test etmek ve bir dosyanın olup olmadığını test etmek gibi operatörler üzerine kuruludur . Her operatörün etrafında bir boşluğa (örn . Değil ) ve parantezlerin içinde ve dışında bir boşluğa veya karaktere (örn . Değil ) ihtiyacınız olduğunu unutmayın.-n "$variable"-e "$file"[ "$x" = "$y" ][ "$x"="$y" ];[ -n "$foo" ][-n "$foo"]
  • [[ … ]]çift ​​parantez ksh / bash / zsh cinsinden birkaç ek özelliğe sahip alternatif bir koşullu ifade biçimidir; örneğin, [[ -L $file && -f $file ]]bir dosyanın normal bir dosyaya sembolik bir bağ olup olmadığını test etmek için yazarken , tekli parantezler gerekir [ -L "$file" ] && [ -f "$file" ]. Bkz tırnaklar olmadan boşluklarla parametre genişletme çift parantez [[fakat tek değil parantez [içinde çalışır mu Neden? bu konuda daha fazla bilgi için.

Kabukta, her komut bir koşullu komuttur: her komut, 0 anlamına gelen bir geri dönüş durumuna veya 1 ile 255 arasında (ve bazı kabuklarda potansiyel olarak daha fazla) başarısızlığa işaret eden bir tamsayıdır. [ … ]Komutu (veya [[ … ]]sözdizimi formu) da hecelenebileceğini belirli bir komuttur test …ve bir dosya var olduğunda başarılı ya da bir dizi boş olmayan olduğunda ya da bir dizi başka daha küçük olduğu zaman, vb ((…))zaman sözdizimi şekilde başarılı bir sayı sıfır değil. İşte bir kabuk betiğinde koşullu birkaç örnek:

  • myfileDize içeriyorsa test edin hello:

    if grep -q hello myfile; then 
  • Eğer mydirbir dizinse, dizine geçin ve bir şeyler yapın:

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
  • myfileGeçerli dizinde adı verilen bir dosya olup olmadığını test edin :

    if [ -e myfile ]; then 
  • Aynı, ancak sarkan sembolik bağlar dahil:

    if [ -e myfile ] || [ -L myfile ]; then 
  • x(Sayısal olduğu varsayılan) değerinin en az 2, taşınabilir olduğunu test edin :

    if [ "$x" -ge 2 ]; then 
  • x(Sayısal olduğu varsayılan) değerinin bash / ksh / zsh cinsinden en az 2 olup olmadığını test edin :

    if ((x >= 2)); then 

Tekli dirseğin -ayerine onu desteklediğine dikkat edin &&, böylece biri yazabilir:, [ -L $file -a -f $file ]köşeli parantezlerin içinde fazladan [ve aynı sayıda karakter olan ]...
Alexis Wilke

6
@AlexisWilke İşleçler -ave -osorunlu çünkü işlenenlerin bazıları işleçlere benziyorsa hatalı ayrıştırmalara yol açabilir. Bu yüzden onlardan bahsetmiyorum: Sıfır avantajları var ve her zaman işe yaramıyorlar. Ve asla iyi bir neden olmadan kodlanmamış değişken açılımlar yazmayın: [[ -L $file -a -f $file ]]iyi, ancak tek parantez içinde ihtiyacınız var [ -L "$file" -a -f "$file" ](örneğin, $fileher zaman /veya ile başlıyorsa tamam ./).
Gilles,

Öyle unutmayın [[ -L $file && -f $file ]](hayır -aile [[...]]varyant).
Stéphane Chazelas

18

Gönderen bash belgelerinde :

(list)liste alt kabuk ortamında yürütülür (bkz. KOMUTANLI YÜRÜTME ORTAMI). Kabuğun ortamını etkileyen değişken atamaları ve yerleşik komutlar, komut tamamlandıktan sonra geçerli olmaz. İade durumu listenin çıkış durumudur.

Başka bir deyişle, 'listede' cdolanların (a gibi ) (ve dışında etkisinin olmadığından emin olun ). Sızıntı tek şey son komutun veya çıkış kodu set -e(bir tür olarak birkaç başka bir hata üretir ilk komutu if, whilevs.)

((expression))İfade, ARİTMETİK DEĞERLENDİRME altında açıklanan kurallara göre değerlendirilir. İfadenin değeri sıfır değilse, dönüş durumu 0'dır; Aksi halde iade durumu 1'dir. Bu "ifade" izin vermek için tam olarak eşdeğerdir.

Bu matematik yapmanıza izin veren bir bash uzantısıdır. Bu, exprtüm sınırlamaları olmadan kullanmaya benzer expr(her yerde boşluk olması, kaçma *vb.)

[[ expression ]]Koşullu ifade ifadesinin değerlendirmesine bağlı olarak 0 veya 1 durumu döndür. İfadeler, KOŞULLU ANLATIMLAR altında aşağıda açıklanan primerlerden oluşur. Sözcük bölme ve yol adı genişletme, [[ve]] arasındaki sözcüklerde gerçekleştirilmez; tilde genişleme, parametre ve değişken genişleme, aritmetik genişleme, komut değiştirme, işlem değiştirme ve fiyat teklifi kaldırma işlemi gerçekleştirilir. -F gibi koşullu operatörler, birincil olarak algılanmak için alıntı yapılmamalıdır.

[[] İle kullanıldığında, <ve> operatörleri geçerli yerel ayarı kullanarak sözlüksel olarak sıralar.

Bu, dizeleri, sayıları ve dosyaları biraz benzer testtekliflerle karşılaştırmak için gelişmiş bir test sunar, ancak daha güçlüdür.

[ expr ]Koşullu ifade expr değerlendirmesine bağlı olarak 0 (doğru) veya 1 (yanlış) durumunu döndür. Her operatör ve oper ve ayrı bir argüman olmalıdır. İfadeler, KOŞULLU ANLATIMLAR altında yukarıda açıklanan primerlerden oluşur. sınama hiçbir seçeneği kabul etmiyor, seçeneklerin sonunu belirtmek için bir argümanı kabul etmiyor ve görmezden geliyor.

[...]

Bu bir çağırır test. Aslında eski günlerde, [sembolik bir bağdı test. Aynı şekilde çalışır ve aynı sınırlamalara sahipsiniz. Bir ikili, başlatıldığı adı bildiğinden, test programı bir parametre bulana kadar parametreleri ayrıştırabilir ]. Eğlenceli Unix hileler.

Durumunda unutmayın bash, [ve testyerleşik işlevler (Bir yorumda gibi), henüz hemen hemen aynı sınırlamalar uygulanır.


1
Her ne kadar testve [tabii ki Bash'te yerleşik komutlar olsa da, muhtemelen harici bir ikili de var.
ilkkachu

1
Dış ikili [, testmodern sistemlerin çoğunda sembolik bir bağ değildir .
Random832

1
Her nasılsa, hem birleştirmeleri, hem de birkaç koşullandırma eklemeleri yerine, tam olarak ihtiyaç duydukları tam iki şeye sahip iki ayrı ikili oluşturmak için uğraşmalarını eğlenceli buluyorum. Gerçi aslında strings /usr/bin/testyardım metni de var, bu yüzden ne diyeceğimi bilemiyorum.
ilkkachu

2
@ Random832 Beklenmeyen arg0 davranışını önlemek için GNU gerekçesiyle ilgili fikrinizi anlıyorum, ancak POSIX gereklilikleri hakkında bu kadar olumlu olmazdım. testKomutun standart tarafından bağımsız bir dosya tabanlı komut olarak bulunması açıkça zorunlu olmakla birlikte , hiçbir şey [varyantının da bu şekilde uygulanması gerektiğini belirtmez. Örneğin, Solaris 11 herhangi bir [çalıştırılabilir özellik sunmuyor , ancak yine de POSIX standartlarıyla tam olarak uyumlu
jlliagre

2
(Çıkış 1) parantez dışında bir etkiye sahiptir.
Alexander,

14

[ vs [[

Bu cevap, sorunun [vs [[alt kümesini kapsayacaktır .

Bash 4.3.11'deki bazı farklılıklar:

  • POSIX vs Bash uzantısı:

  • Düzenli emir vs büyü

    • [ garip bir isimle sadece düzenli bir komuttur.

      ]sadece [daha fazla argümanın kullanılmasını önleyen bir argümandır .

      Ubuntu 16.04 aslında /usr/bin/[coreutils tarafından sağlananlar için çalıştırılabilir bir dosyaya sahip ancak bash yerleşik sürümü öncelikli.

      Hiçbir şey Bash'in emri ayrıştırdığı şekilde değişmez.

      Özellikle, <yönlendirme &&ve ||birden çok komutu birleştirmek, ( )kaçmadıkça alt kabuklar oluşturur \ve sözcük genişletme her zamanki gibi olur.

    • [[ X ]]Xsihirli bir şekilde ayrıştırılan tek bir yapıdır . <, &&, ||Ve ()özel olarak muamele edilmiş ve kelime bölme kuralları farklı olabilirler.

      =Ve gibi başka farklılıklar da vardır =~.

      Bashese dilinde: [yerleşik bir komuttur ve [[bir anahtar kelimedir: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && ve ||

    • [[ a = a && b = b ]]: doğru, mantıklı ve
    • [ a = a && b = b ]: &&bir AND komut ayırıcı olarak ayrıştırılan sözdizimi hatasıcmd1 && cmd2
    • [ a = a -a b = b ]: eşdeğer, ancak POSIX tarafından onaylanmadı.
    • [ a = a ] && [ b = b ]: POSIX ve güvenilir eşdeğeri
  • (

    • [[ (a = a || a = b) && a = b ]]: yanlış
    • [ ( a = a ) ]: sözdizimi hatası, ()alt kabuk olarak yorumlanır
    • [ \( a = a -o a = b \) -a a = b ]: eşdeğer, ancak ()POSIX tarafından kullanımdan kaldırıldı
    • { [ a = a ] || [ a = b ]; } && [ a = b ]POSIX eşdeğeri 5
  • genişlemelerde sözcük bölme ve dosya adı oluşturma (split + glob)

    • x='a b'; [[ $x = 'a b' ]]: true, tırnak gerekli değil
    • x='a b'; [ $x = 'a b' ]: sözdizimi hatası, genişler [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: geçerli dizinde birden fazla dosya varsa, sözdizimi hatası.
    • x='a b'; [ "$x" = 'a b' ]: POSIX eşdeğeri
  • =

    • [[ ab = a? ]]: true, çünkü desen eşleşmesi yapıyor ( * ? [sihir). Glob, geçerli dizindeki dosyalara genişlemez.
    • [ ab = a? ]: a?glob genişler. Bu nedenle, geçerli dizindeki dosyalara bağlı olarak doğru veya yanlış olabilir.
    • [ ab = a\? ]: false, glob genişlemesi değil
    • =ve ==her ikisi de aynıdır [ve [[ancak ==bir Bash uzantısıdır.
    • case ab in (a?) echo match; esac: POSIX eşdeğeri
    • [[ ab =~ 'ab?' ]]: yanlış 4 , sihirini kaybeder''
    • [[ ab? =~ 'ab?' ]]: doğru
  • =~

    • [[ ab =~ ab? ]]: true, POSIX düzenli ifade eşleşmesini ?genişletti , genişlemiyor
    • [ a =~ a ]: sözdizimi hatası. Bash eşdeğeri yok.
    • printf 'ab\n' | grep -Eq 'ab?': POSIX eşdeğeri (yalnızca tek satırlı veriler)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX eşdeğeri.

Öneri : daima kullanın [].

[[ ]]Gördüğüm her yapı için POSIX eşdeğeri var .

Eğer seni kullanırsan [[ ]]:

  • taşınabilirliğini kaybetmek
  • okuyucuyu başka bir bash uzantısının inceliklerini öğrenmeye zorlamak. [garip bir isimle sadece düzenli bir komuttur, özel bir anlambilim söz konusu değildir.

[[...]]Korn kabuğundaki eşdeğer yapıdan esinlenmiştir

² ama bazı değerler için başarısız aveya b(gibi +ya index) ve eğer sayısal bir karşılaştırma yapar ave bondalık tamsayılar benziyor. expr "x$a" '<' "x$b"her ikisi de çalışır.

³ ve ayrıca aveya bbenzeri !veya bazı değerleri için başarısız olur (.

4 Bash 3.2 ve yukarıda ve 3.1 vurmayı sağlanan uyumluluk (olduğu gibi etkin değildir BASH_COMPAT=3.1)

5 ( gereksiz bir alt kabuk çalıştıracak olan {...;}komut grubu ile burada) gruplama (...)gerekli değildir ||ve &&kabuk operatörleri ( ||ve && [[...]]operatörler veya -o/ -a [operatörler aksine ) eşit önceliğe sahip olduğundan gerekli değildir. Yani [ a = a ] || [ a = b ] && [ a = b ]eşdeğer olurdu.


@ StéphaneChazelas bilgi için teşekkürler! Ben exprcevaba ekledim . "Bash eklentisi" terimi, Bash'in bazı sözdizimi ekleyen ilk kabuk olduğu anlamına gelmez, POSIX sh öğrenme vs Bash zaten beni çıldırtıyor.
Ciro Santilli

Bak , kayboldun man testmu denedin mi man [. Bu POSIX değişkeni açıklayacaktır.
Jonathan Komar

13

Bazı örnekler:

Geleneksel test:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

testve [diğerleri gibi komutlardır, bu yüzden değişken tırnak içinde olmadıkça kelimelere bölünür.

Yeni tarz testi

[[ ... ]] biraz farklı çalışan (daha yeni) özel bir kabuk yapısıdır, en belirgin olanı sözcük bölme değişkenleri olmamasıdır:

if [[ -n $foo ]] ; then... 

Ve burada bazı belgeler[[[ .

Aritmetik testi:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

"Normal" komutları:

Yukarıdakilerin tümü normal komutlar gibi davranır ve ifherhangi bir komutu alabilir:

# grep returns true if it finds something
if grep pattern file ; then ...

Birden çok komut:

Veya birden çok komut kullanabiliriz. Bir komut kümesini ( ... )sarmalamak, alt kabukta çalıştırılarak kabuğun durumunun geçici bir kopyasını oluşturur (çalışma dizini, değişkenler). Bir programı geçici olarak başka bir dizinde çalıştırmamız gerekirse:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...

1

Gruplandırma Komutları

Bash, bir birim olarak yürütülecek komut listesini gruplandırmak için iki yol sağlar.

( list )Parantezler arasına bir komut listesi yerleştirmek, bir alt kabuk ortamının oluşturulmasına ve listedeki komutların her birinin bu alt kabukta yürütülmesine neden olur. Liste bir alt kabukta yürütüldüğünden, alt kabuk tamamlandıktan sonra değişken atamaları etkin kalmaz.

$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
inside: a=2
outside: a=1

{ list; }Kıvrımlı ayraçlar arasına bir komut listesi yerleştirmek, listenin geçerli kabuk bağlamında yürütülmesine neden olur . Alt kabuk oluşturulmaz. Aşağıdaki liste noktalı virgül (veya yeni satır) gereklidir. Kaynak

${} Parameter expansion Ex:  ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s
$() Command substitution Ex: result=$(COMMAND) 
$(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

Koşullu Yapılar

Tek Parantez yani []
Karşılaştırma için ==, !=, <,ve >ve kullanılmalıdır ve sayısal karşılaştırma için eq, ne,ltve gtkullanılmalıdır.

Geliştirilmiş Konsollar, yani[[]]

Yukarıdaki tüm örneklerde, koşullu ifadeyi içine almak için sadece tek parantezler kullandık, ancak bash, tek parantez sözdiziminin gelişmiş bir sürümü olarak hizmet eden çift parantezlere izin verir.

Karşılaştırma yapmak için ==, !=, <,ve >kelimenin tam anlamıyla kullanabilirsiniz.

  • [, test komutunun eş anlamlısıdır. Kabuğun içine yerleştirilse bile yeni bir işlem yaratır.
  • [[ bir program değil, bir anahtar kelime olan yeni bir geliştirilmiş sürümüdür.
  • [[Kornve tarafından anlaşılmaktadır Bash.

Kaynak

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.