Bash'ta çift ve tek köşeli ayraçlar arasındaki fark nedir?


426

Tam olarak aradaki farkın ne olduğunu merak ettim.

[[ $STRING != foo ]]

ve

[ $STRING != foo ]

Bunun dışında, ikincisi posix uyumludur, sh'de bulunur ve birincisi bash'ta bulunan bir uzantıdır.


1
Ayrıca hiç parantez kullanmak istemediğinizi merak ediyorsanız, örneğin bir ififade bağlamında , bkz. Mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D
Kev

ayrıca, Ubuntu'nun dokümanlarından: wiki.ubuntu.com/…
radistao

Yanıtlar:


309

Birkaç fark var. Bence en önemlilerinden bazıları:

  1. [Bash ve diğer birçok modern kabuğunda yerleşiktir. Yerleşik bir kapanış gerekliliği ile [benzerdir . Komutlar geriye dönük olarak uyumlu olacak şekilde yerleşikler ve işlevselliklerini ve sınırlamaları ile birlikte bunları taklit ederler . Orijinal yürütülebilir dosyalar halen POSIX uyumluluğu ve geriye dönük uyumluluk için hala mevcuttur. Komutu Bash'de çalıştırmak, bunun varsayılan olarak yerleşik olarak yorumlandığını gösterir . (Not: yalnızca PATH üzerindeki yürütülebilir dosyaları arar ve buna eşittir )test][test/bin/[/bin/testtype [[which [type -p [
  2. [[o kadar uyumlu değil, mutlaka neye /bin/shişaret ettiği ile çalışmak olmaz . Yani [[daha modern Bash / Zsh / Ksh seçeneğidir.
  3. [[Kabukta yerleşik olduğundan ve eski gerekliliklere sahip olmadığından, boşluklu bir dizeye değer veren değişkenleri karıştırmak için IFS değişkenine dayalı kelime bölme konusunda endişelenmenize gerek yoktur . Bu nedenle, değişkeni çift tırnak içine almanıza gerek yoktur.

Çoğunlukla, geri kalanı sadece daha hoş bir sözdizimidir. Daha fazla fark görmek için bu bağlantıyı bir SSS cevabına tavsiye ediyorum: Test, [ve [[?] Arasındaki fark nedir? . Aslında bash komut dosyası yazma konusunda ciddiysen , SSS, Tuzaklar ve Rehber dahil tüm wikileri okumanı öneririm . Kılavuz bölümündeki test bölümü de bu farklılıkları açıklar ve taşınabilir olmaktan endişe duymanıza gerek kalmıyorsa neden yazarların daha iyi bir seçim olduğunu düşünüyor . Ana nedenler:[[

  1. Testin sol tarafını alıntı yapmak için endişelenmenize gerek yoktur, böylece aslında bir değişken olarak okunur.
  2. < >Girdi yönlendirme olarak değerlendirilmemeleri için ters eğik çizgilere göre daha az ve daha fazla kaçmanız gerekmez , bu da dosyaların üzerine yazarak bazı şeyleri gerçekten karıştırabilir. Bu yine [[bir yerleşik olmak için geri gider . [(Test) harici bir programsa, kabuğun değerlendirdiği şekilde bir istisna yapması gerekir <ve >sadece /bin/testçağrılırsa, bu gerçekten mantıklı olmaz.

5
Teşekkürler, bash SSS bağlantısı aradığım şeydi (bu sayfa hakkında hiçbir şey bilmiyordum, teşekkürler).
0x89

2
Gönderinizi bu bilgilerle düzenledim, ancak [ve test yerleşik olarak yürütülür. Yerleşikler / bin / [ve / bin / test'in yerini alacak şekilde tasarlanmıştır, ancak ikili dosyaların sınırlarını da çoğaltmak için gerekliydi. 'Type [' komutu, yerleşimin kullanıldığını doğrular. 'hangi [', PATH üzerinde yalnızca yürütülebilir dosyaları arar ve '-P ['
eşine eşittir

133

Kısacası:

[bir bash yerleşiktir

[[]] bash Anahtar Kelimeler

Anahtar Kelimeler: Anahtar kelimeler yerleşik yapılara benzer, ancak temel fark, özel ayrıştırma kurallarının kendileri için geçerli olmasıdır. Örneğin, [bir bash yerleşimidir, [[bir bash anahtar sözcüğüdür). Her ikisi de malzeme testi için kullanılır, ancak [[bir yerleşik değil, bir anahtar kelime olduğundan, onu çok kolaylaştıran birkaç özel ayrıştırma kuralından yararlanır:

  $ [ a < b ]
 -bash: b: No such file or directory
  $ [[ a < b ]]

İlk örnek bir hata verir çünkü bash b dosyasını [a] komutuna yönlendirmeye çalışır. İkinci örnek aslında beklediğiniz şeyi yapar. <Karakterinin artık Dosya Yönlendirme işlecinin özel bir anlamı yoktur.

Kaynak: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments


3
[bir POSIX kabuk komutu; yerleşik olması gerekmiyor. ]sadece bu komutun aradığı bir argümandır, böylece sözdizimi dengelenir. Komut, bunun bir kapanış aramaması testdışında eşanlamlıdır . test]
Kaz


81

Davranış farklılıkları

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.


Nasıl kullanmak printf 'ab' | grep -Eq 'ab?'içinde if [ … ]?
meeDamian

1
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. []tıpkı bunun gibi bir komuttur grep. Bu ()komutta gerekli olmayabilir, emin değilim: Çünkü, |Bash'in nasıl ayrıştırdığına bağlı olarak ekledim . Eğer hayır |olmasaydı sadece yazabileceğinden eminim if cmd arg arg; then.
Ciro Santilli 事件

1
@meeDamian evet, buna gerek yok ()gibi görünüyor: stackoverflow.com/questions/8965509/…
Ciro Santilli,

1
Güzel liste! Ayrıca bakınız: wiki.ubuntu.com/…
radistao

5

Tek Braket, yani []şartlı bir ifadeyi içine almak için uyumlu POSIX kabuğudur.

İkili Parantez, yani [[]]standart POSIX versiyonunun geliştirilmiş (veya genişletme) bir versiyonudur, bu bash ve diğer kabuklar (zsh, ksh) tarafından desteklenir.

Bash olarak, kullandığımız sayısal karşılaştırma için eq, ne, ltve gtkarşılaştırma için çift parantez ile kullanabileceğimiz ==, !=, <,ve >tam anlamıyla.

  • [, 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.

Örneğin:

[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory 
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works

4

Manpage'in ilgili bölümlerinin hızlı bir şekilde okunmasına dayanarak, temel fark, ==ve !=operatörlerin değişmez bir dize yerine bir örüntü ile eşleşmesi ve ayrıca =~regex karşılaştırma işlecinin bulunmasıdır.

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.