Bash'de çift köşeli parantez [[]] tek köşeli parantez [] yerine tercih edilebilir mi?


574

Bir meslektaş, yakın zamanda bir kod incelemesinde yapının aşağıdaki gibi yapılarda [[ ]]tercih edileceğini iddia etti[ ]

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

Bir gerekçe sağlayamadı. Bir tane var mı?


19
Bazen kendinizi onun derin açıklama :) Farklı gerektirmeden bir tavsiye dinlemek için izin, esnek olun [[kod iyi ve net onunla, ama o gün hatırlıyorum da liman olacak değil varsayılan kabuk ile sistem üzerinde scriptworks bashveya ksh, vb. [çirkin, hantal ama AK-47her durumda olduğu gibi çalışıyor .
kale

178
@rook Derin bir açıklama yapmadan bir tavsiyeyi dinleyebilirsiniz, elbette. Ancak bir açıklama istediğinizde ve bunu anlamadığınızda, genellikle kırmızı bir bayraktır. "Güven, ama doğrula" ve tüm bunlar.
Josip Rodin

6
Ayrıca bakınız: Bash operatörleri arasındaki fark nedir [[vs [vs (vs ((? Üzerinde Unix & Linux SE.
codeforester

1
Diğer bir deyişle "söylediklerinizi yapın ve soru sormayın"
glyph

@rook Bu hiç mantıklı değil.
Rakib

Yanıtlar:


607

[[daha az sürpriz içerir ve genellikle kullanımı daha güvenlidir. Ancak taşınabilir değil - POSIX ne yaptığını belirtmiyor ve sadece bazı kabuklar onu destekliyor (bash'ın yanında ksh'ın da desteklediğini duydum). Örneğin,

[[ -e $b ]]

bir dosyanın var olup olmadığını sınamak için. Ancak [, alıntı $byapmalısınız, çünkü argümanı böler ve gibi şeyleri genişletir "a*"( [[kelimenin tam anlamıyla alır). Bu aynı zamanda [harici bir programın nasıl olabileceği ile de ilgilidir ve argümanını normalde diğer tüm programlar gibi alır (aynı zamanda yerleşik de olabilir, ancak yine de bu özel işleme sahip değildir).

[[ayrıca =~C benzeri dillerde bilindiği gibi operatörlerle düzenli ifade eşleşmesi gibi başka güzel özelliklere de sahiptir . : İşte bu konuda iyi bir sayfası nedir testi arasındaki fark, [ve [[? ve Bash Testleri


21
Bu günlerde bash'ın her yerde olduğu düşünüldüğünde, oldukça taşınabilir olduğunu düşünüyorum. Benim için tek yaygın istisna meşgul kutusu platformlarında - ama muhtemelen üzerinde çalıştığı donanım göz önüne alındığında, bunun için özel bir çaba sarf etmek istersiniz.
silahlar

14
@guns: Gerçekten. İkinci cümlenizin ilk cümlenizi çürüttüğünü öneririm; yazılım geliştirmeyi bir bütün olarak düşünürseniz, "bash her yerde" ve "istisna meşgul kutusu platformları" tamamen uyumsuzdur. Meşgul kutusu gömülü geliştirme için yaygındır.
Yörüngedeki Hafiflik Yarışları

11
@guns: Kutumda bash yüklü olsa bile, komut dosyasını yürütmeyebilir (FreeBSD ve Ubuntu'da standart olduğu gibi / bin / sh bazı tire değişkenlerine sembolize edilmiş olabilir). Busybox'ta da ek gariplik var: günümüzde standart derleme seçenekleriyle, ayrıştırıyor [[ ]]ancak aynı anlama geliyor [ ].
dubiousjim

59
@dubiousjim: Yalnızca bash yapılarını (bu gibi) kullanıyorsanız, #! / bin / sh değil #! / bin / bash olmalıdır.
Nick Matteo

16
Bu yüzden scriptlerimi kullanıyorum #!/bin/shama daha sonra #!/bin/bashBourne kabuğunun taşınabilir olmadığını belirtmek için bazı BASH'a özgü özelliklere güvenir etmez kullanmaya başlarım.
Anthony

151

Davranış farklılıkları

Bash 4.3.11 ile ilgili bazı farklılıklar:

  • POSIX vs Bash uzantısı:

  • normal komut vs büyü

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

      ]sadece [başka bir argümanın kullanılmasını engelleyen bir argüman .

      Ubuntu 16.04 aslında coreutils/usr/bin/[ tarafından sağlanan bir yürütülebilir dosyaya sahiptir , ancak bash yerleşik sürümü önceliklidir.

      Hiçbir şey Bash'in komutu ayrıştırma biçiminde değiştirilmez.

      Özellikle, <yeniden yönlendirme &&ve ||birden çok komutu birleştirmek, ( )kaçmadığı sürece alt kabuklar üretir \ve kelime genişletme her zamanki gibi gerçekleşir.

    • [[ 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'de: [yerleşik bir komuttur ve [[bir anahtar kelimedir: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && ve ||

    • [[ a = a && b = b ]]: doğru, mantıklı ve
    • [ a = a && b = b ]: sözdizimi hatası, &&AND komut ayırıcısı olarak ayrıştırıldıcmd1 && cmd2
    • [ a = a -a b = b ]: eşdeğer, ancak POSIX³ tarafından kullanımdan kaldırıldı
    • [ 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⁵
  • sözcük bölme ve genişletmelerde dosya adı oluşturma (split + glob)

    • x='a b'; [[ $x = 'a b' ]]: true, tırnak işaretleri gerekmez
    • x='a b'; [ $x = 'a b' ]: sözdizimi hatası, [ 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? ]]: doğru, çünkü desen eşleşmesi yapıyor ( * ? [sihir). 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\? ]: yanlış, 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?' ]]: false⁴, büyüsünü kaybeder ''
    • [[ ab? =~ 'ab?' ]]: doğru
  • =~

    • [[ ab =~ ab? ]]: doğru, POSIX genişletilmiş düzenli ifade eşleşmesi, ?genişlemeyi engellemez
    • [ 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.

Tavsiye : her zaman kullanın [].

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

Sizi kullanırsanız [[ ]]:

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

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

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

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

3.2 bash 3.2 ve üstü sürümlerde ve bash 3.1 ile uyumluluk sağlanmadığında (ile olduğu gibi BASH_COMPAT=3.1)

Shell ve kabuk işleçleri ( ve işleçlerin veya / işleçlerin aksine ) eşit önceliğe sahip olduğundan gruplama (burada {...;}bunun yerine (...)gereksiz bir alt kabuk çalıştıracak olan komut grubu ile birlikte ) gerekli değildir . Yani eşdeğer olur.||&&||&& [[...]]-o-a [[ a = a ] || [ a = b ] && [ a = b ]


4
İyi açıklamalar. Kullandığım [aynı nedenlerle.
Gordon

2
Bashese'de :) ha. POSIX'e bağlı kalmak için farklılıkları ve nedeni güzel bir şekilde açıklamak.
Jonathan Komar

56

[[ ]]daha fazla özelliğe sahiptir - Daha fazla bilgi için Gelişmiş Bash Komut Dosyası Kılavuzu'na , özellikle Bölüm 7'deki genişletilmiş test komutu bölümüne göz atmanızı öneririm .

Bu arada, kılavuz notları olarak, [[ ]]ksh88'de (Korn kabuğunun 1988 versiyonu) tanıtıldı.


5
Bu bir bashizmden uzak, ilk önce Korn kabuğunda tanıtıldı.
Henk Langeveld

6
@Thomas, ABS aslında birçok çevrede çok zayıf bir referans olarak kabul edilir; çok fazla doğru bilgiye sahip olmasına rağmen, örneklerinde kötü uygulamalar sergilemekten kaçınmak için çok az dikkat gösterme eğilimindedir ve hayatının büyük bir kısmını bakıma harcamamıştır.
Charles Duffy

@CharlesDuffy Yorumunuz için teşekkürler, iyi bir alternatif adlandırabilirsiniz. Kabuk kodlama uzmanı değilim, yaklaşık her yarım yılda bir senaryo yazmak için danışabileceğim bir rehber arıyorum.
Thomas

9
@Thomas, Wooledge BashFAQ ve ilişkili wiki kullandığım şeyler; Freenode #bash kanalının sakinleri tarafından aktif olarak korunurlar (bazen dikenli olsa da doğruluk konusunda derinden ilgilenme eğilimi gösterirler). BashFAQ # 31, mywiki.wooledge.org/BashFAQ/031 , bu soruyla doğrudan alakalı sayfadır.
Charles Duffy

13

Gönderen hangisi karşılaştırıcı test, destek veya çift parantez, en hızlı? ( http://bashcurescancer.com )

Çift braket, test ve tek braketin kabuk yerleşik olduğu (ve gerçekte aynı komut olduğu) bir “bileşik komut” dur. Böylece, tek parantez ve çift parantez farklı kod yürütür.

Test ve tek parantez ayrı ve harici komutlar olarak var olduklarından en taşınabilir olanlardır. Ancak, BASH'in herhangi bir uzaktan modern sürümünü kullanıyorsanız, çift braket desteklenir.


7
Kabuk senaryolarında en hızlı saplantı nedir ? Ben en taşınabilir istiyorum ve iyileştirme [[getirebilir hakkında daha az bakım olabilir. Ama sonra ben eski bir okul yaşlı osuruyum :-)
Jens

1
Birçok merminin yerleşik versiyonlarını kanıtladığını [ve testharici versiyonlar da mevcut olduğunu düşünüyorum.
dubiousjim

4
@Jens genel olarak kabul ediyorum: komut dosyalarının tüm amacı taşınabilirliktir (aksi halde, komut dosyası değil kodlar ve derleriz) ... düşünebileceğim iki istisna şunlardır: (1) sekme tamamlama (nerede tamamlama komut dosyaları, çok sayıda koşullu mantıkla gerçekten uzun sürebilir); ve (2) süper istemler ( PS1=...crazy stuff...ve / veya $PROMPT_COMMAND); bunlar için , betiğin yürütülmesinde herhangi bir algılanabilir gecikme istemiyorum .
michael

1
En hızlı saplantılardan bazıları basitçe stildir. Diğer her şey eşitse, neden daha verimli kod yapısını varsayılan stilinize dahil etmiyorsunuz, özellikle de bu yapı daha fazla okunabilirlik sunuyorsa? Taşınabilirliğe gelince, bash için uygun olan birçok görev doğal olarak taşınabilir değildir. Örneğin, apt-get updateson çalıştırıldığından bu yana X saatten uzun bir süre geçtiyse koşmam gerekiyor . Taşınabilirliğin kod için zaten çok uzun kısıtlamalar listesinin dışında bırakılabilmesi büyük bir rahatlamadır.
Ron Burk

5

Aşağıdaki Google'ın stil kılavuzuna giriyorsanız :

Test edin [ve[[

[[ ... ]]Hiçbir yol adı genişlemesi olarak hataları azaltır veya kelime bölme arasında gerçekleşir [[ve ]]ve [[ ... ]]düzenli ifade eşleştirmesi için izin verir [ ... ]yapmaz.

# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
  echo "Match"
fi

# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
  echo "Match"
fi

# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
  echo "Match"
fi

1
Google, " hiçbir yol adı genişletmesi yok ... gerçekleşiyor " yazdı ancak [[ -d ~ ]]true ~değerini döndürdü (bu genişletildi anlamına gelir /home/user). Google'ın yazarken daha hassas olması gerektiğini düşünüyorum.
JamesThomasMoon1979

2

[[Kullanamayacağınız tipik bir durum bir autotools configure.ac komut dosyasındadır, parantezlerin özel ve farklı bir anlamı vardır, bu nedenle veya - testyerine kullanmanız gerekecek ve bu testin aynı program olduğunu unutmayın.[[[[


2
Verilen otomatik araçlar bir POSIX kabuğu değildir, neden hiç [POSIX kabuğu işlevi olarak tanımlanmayı beklersiniz ?
Gordon

Çünkü autoconf betiği bir kabuk betiğine benziyor ve bir kabuk betiği üretiyor ve çoğu kabuk komutu onun içinde çalışıyor.
vy32

-1

[[]] çift köşeli ayraçlar SunOS'un belirli sürümü altında desteklenmez ve işlev bildirimleri içinde tamamen desteklenmez: GNU bash, sürüm 2.02.0 (1) -çalışma (sparc-sun-solaris2.6)


1
çok doğru ve hiç de önemsiz değil. eski sürümlerde bash taşınabilirliği dikkate alınmalıdır. İnsanlar "bash her yerde ve taşınabilirdir, belki hariç (buraya ezoterik işletim sistemi ekleyin) " - ama benim deneyimime göre solaris, taşınabilirliğe özel dikkat gösterilmesi gereken platformlardan biridir: sadece eski bash sürümlerini dikkate almak için değil yeni işletim sistemleri, diziler, işlevler vb. ile ilgili sorunlar / hatalar; ancak tr, sed, awk, tar gibi yardımcı programlarda (komut dosyalarında kullanılır) bile solaris üzerinde çalışmanız gereken tuhaflıklar ve özellikler vardır.
michael

2
çok haklısın ... Solaris'te POSIX olmayan pek çok yardımcı program, sadece "df" çıktısına ve argümanlarına bak ... Umarım yavaş yavaş kaybolur (Kanada hariç).
çöpçü

7
Solaris 2.6 mı ciddi? 1997'de piyasaya sürüldü ve 2006'da desteği sonlandırdı. Sanırım hala kullanıyorsan başka sorunların var !. Bu arada, çift parantez tanıtan Bash v2.02'yi kullandı, bu yüzden bu kadar eski bir şey üzerinde bile çalışmalı. 2005'ten Solaris 10, Bash 3.2.51 ve 2011'den Solaris 11, Bash 4.1.11'i kullanıyor.
peterh

1
Script taşınabilirliği. Linux sistemlerinde genellikle her aracın yalnızca sürümü vardır ve bu GNU sürümüdür. Solaris'te genellikle bir Solaris yerel sürümü veya GNU sürümü arasında seçim yapabilirsiniz (örneğin Solaris tar vs GNU tar). GNU'ya özgü uzantılara bağımlıysanız, komut dosyasında taşınabilir olması için bunu belirtmeniz gerekir. Solaris'de bunu GNU grep'i istiyorsanız "g" ön ekiyle, örneğin `ggrep` ile yapabilirsiniz.
peterh

-2

Özetle, [[daha iyidir çünkü başka bir işlemi çatallamaz. Hiçbir parantez veya tek bir parantez, başka bir işlemi çatalladığı için çift parantezden daha yavaştır.


8
Test ve [, bash'ta aynı yerleşik komutun adlarıdır. Bunu type [görmek için kullanmayı deneyin .
AB

1
@alberge, bu doğrudur, ancak [[, farklı olarak [, bash komut satırı yorumlayıcısı tarafından sözdizimi yorumlanır. Bash yazmayı deneyin type [[. unix4linux, klasik Bourne-kabuk [testlerinin doğruluk değerini belirlemek için yeni bir süreci kırmasına rağmen , [[sözdiziminin (bash, zsh, vb.
Tim Gilbert

2
@Tim, hangi Bourne kabuğundan bahsettiğinizden emin değilim, ancak [Bash ve Dash ( /bin/shDebian'dan türetilen tüm Linux dağıtımlarında) yerleşik .
AB

1
Ne demek istediğini anlıyorum, bu doğru. Eski Solaris veya HP / UX sistemlerinde / bin / sh gibi bir şey düşünüyordum, ama elbette kullanmamanız gerekenlerle uyumlu olmanız gerekiyorsa [[.
Tim Tim

1
@alberge Bourne kabuğu Bash değildir ( Bourne Again SHell olarak da bilinir ).
kiamlaluno
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.