Test veya [veya [[bash mermileri arasında ve diğer mermiler arasında daha mı taşınabilir?


44

Yapabileceğimi görüyorum

$ [ -w /home/durrantm ] && echo "writable"
writable

veya

$ test -w /home/durrantm && echo "writable"
writable

veya

$ [[ -w /home/durrantm ]] && echo "writable"
writable

Üçüncü sözdizimini kullanmayı seviyorum. Her yönden ve tüm olumsuz ve ileri vakalar için eşdeğer mi? Taşınabilirlikte, örneğin Ubuntu'daki bash ile OS X veya daha eski / daha yeni bash sürümleri arasında, örneğin 4.0'dan önce / sonra ve her ikisi de ifadeleri aynı şekilde genişletiyor mu?


2
İçin [ … ]vs [[ … ]]vs test …, daha eksiksiz cevaplar vardır bu çoğunlukla yinelenen soru .
Gilles 'SO- kötülükten


1
Bir deyiş vardır: "taşınabilir bir kod yoktur, yalnızca taşınan kod vardır". Bununla ilgili tavsiyem: En okunabilir formu kullanın (muhtemelen [[...]]) ve desteklemek istediğiniz tüm platformlarda deneyin. Senaryolarınızı gizlemekte pek bir fayda yoktur, bu yüzden ne sizin ne de hedef kitlenizin kullandığı eski platformlarda çalışırlar. Bu sadece kodunuzu okumayı zorlaştıracak, gereksiz hatalar ve hatta güvenlik sorunları (openssl için olduğu gibi) tanıtacaktır.
stefan.schwetschke

Yanıtlar:


31

[testkomutun eş anlamlısıdır ve aynı anda bir bash yerleşik ve ayrı komuttur. Ancak [[bir bash anahtar sözcüğüdür ve yalnızca bazı sürümlerde çalışır. Bu yüzden taşınabilirlik nedeniyle tekli []veyatest

[ -w "/home/durrantm" ] && echo "writable"

2
[yerleşik veya Bash yerleşik nedir?
Sandburg

@Sandburg POSIX bir standarttır, dolayısıyla yerleşik yapılara sahip olamaz. Tercümana bir şey inşa edilip edilmeyeceğini, sadece ne yapması gerektiğini tanımlamaz. Bu kurallar formları, hem uygulanır testve [hem. Eğer bir kabuk değerlendirmeyi kendi başına yapabilirse, bu size bir işlem kazandırır ve biraz daha hızlı bir hale getirir, ancak sonuç aynı olmak zorundadır.
Bachsau

Sandburg'un davranışının [POSIX tarafından tanımlanıp tanımlanmadığına dair sorusunu hala yanıtlamayan @Bachsau ve bu nedenle maksimum taşınabilirlik (yanılmıyorsam bu sorunun tüm noktası gibi görünüyor)
JamesTheAwesomeDude

@Sandburg (ve bunun karşısında tökezleyen başka kimseye): Evet, her ikisine de benziyor [ve test POSIX . İkisi de "tavsiye testedilmedi" gibi görünüyor, ancak aralarındaki tek fark (?) , "-" argümanını [seçeneklerin sonunu belirten bir sınırlayıcı olarak] "tanımayacağı" (? - bunu ima eden). -" edilir sonu argümanlar için olarak kabul [... aslında zaten iyi bir test durumu ile gelip olamaz, hangi olacak IMO, Kullan ama sapmak [zarif görünüyor, ama testisclearly bir komut)
JamesTheAwesomeDude

35

Evet, farklılıklar var. En taşınabilir testveya [ ]. Bunlar POSIX testşartnamesinin bir parçasıdır .

if ... fiBu yapı, bir POSIX'deki tarafından tanımlanan ve tamamen taşınabilir olmalıdır.

[[ ]]Bir olduğu kshda bazı sürümlerinde mevcuttur özelliği bash( tüm modern olanları içinde,) zshve belki de diğerlerinde ancak bulunmaz shveya dashveya diğer çeşitli basit kabukları.

Yani, sizin komut taşınabilir hale kullanmak [ ], testya da if ... fi.


10
Sadece not etmek bashve çok uzun süredir zshdestekledim [[( bashbunu 90'ların sonlarına, en geç zsh2000'den sonra ekledim ve hiç desteğim olmasa şaşırdım ), bu yüzden ikisinin de bir versiyonuyla karşılaşmanız pek mümkün değil [[. POSIX uyumlu farklı bir kabukla (örneğin dash) karşılaşmak çok daha olasıdır.
chepner

1
Bunun ilginç bir özelliği, [[parametre genişletmelerinin alıntılanması gerekmemesidir: boşluk karakterleri içeriyorsa [[-f $file]]olay çalışır $file.
kasap

2
Düzenli ifadeler yerleşik, ayrıca @helpermethod[[ $a =~ ^reg.*exp.*$' ]]
GSMH

20

Lütfen dikkat, inşaat ile [] && cmdaynı değildir if .. fi.

Bazen onun davranışı oldukça benzer ve [] && cmdbunun yerine kullanabilirsiniz if .. fi. Ama sadece bazen. Eğer birden fazla koşula sahipseniz, koşulu yerine getirmek için bir komutunuz varsa ya if .. else .. fida dikkatli olmanız ve mantığa bakmanız gerekir .

Birkaç örnek:

[ -z "$VAR" ] && ls file || echo wiiii

Aynı değil

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

çünkü lsbaşarısız olursa, echoolmayacak olan idam edilecek if.

Başka bir örnek:

[ -z "$VAR" ] && ls file && echo wiii

aynı değil

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

yine de bu inşaat aynı şekilde hareket edecek

[ -z "$VAR" ] && { ls file ; echo wiii ; }

yankıdan ;sonra önemli olduğunu ve orada olması gerektiğini lütfen unutmayın .

Yani yukarıdaki ifadeye devam ederek diyebiliriz

[] && cmd == eğer ilk komut başarılı olursa bir sonrakini yürütün

if .. fi == koşulu (aynı zamanda test komutu olabilir) daha sonra komutları çalıştırın

Taşınabilirlik için aralarında Yani [ve [[kullanmak [sadece.

ifPOSIX uyumludur. Eğer var ise arasında seçim yapmak [ve ifsizin görev ve beklenen davranışlara bakmak seçin.


Muhtemelen sadece yoğunlaşıyorum, ancak farkın ne olacağını göremiyorum ... lütfen bu iki yapının farklı sonuçlar vereceği bir örnek verebilir misiniz?
kötülük

1
@ evilsoup, güncellendi. En iyi açıklayıcı değilim olabilirim, umarım şimdi açık olacaktır.
acele

1
Çok iyi puan, acele. Ben senin 1 örnek güvenli bir formu olacağını varsayalım: [ -z "$VAR" ] && { ls file; true; } || echo wiiii. Biraz daha ayrıntılı, ama yine de if...fiinşaattan daha kısa .
PM 2Ring

Sorunun [vs [[test vs] hakkında olup olmadığına da değinilirse eğer ... fi vs & & ONE soru olsun diye. Ne yazık ki bunu yapmak, bu cevabı off-point görünüyor. Soruyu cevaplayamadığım için özür dileyerek başlangıçta buna odaklandım. Yaşa ve öğren (dene). :)
Michael Durrant

Oy vermedim çünkü a) bu temel olarak iyi bir cevap, ancak farklı bir sorunun cevabı. b) siz [ve ifaltyazı olarak sunuyorsunuz, ama değiller. Aslında bu &&yerini alıyor if. [bazı kodları çalıştırır lsve grepister gibi ister bir durum döndürür . ifif 'den sonra verilen komutun (deyimin) geri dönüş durumuna bağlı olarak yürütmeyi daldırır, herhangi bir komut (deyim) olabilir. &&Bir sonraki ifadeyi sadece bir önceki basit 0 gibi döndüğünde döndürür if..then..fi.
GnP

9

Aslında bu &&şunun yerine ifdeğil test: ifkabuk komut dosyasındaki bir ifade, bir komutun "başarılı" (sıfır) çıkış durumu döndürdüğünü test eder; Örnekte, komut [.

Yani, aslında burada değiştirdiğiniz iki şey var: testi çalıştırmak için kullanılan komut ve testin sonucuna dayanarak kodu çalıştırmak için kullanılan sözdizimi.

Test komutları:

  • testolan bir standardize komut dizeleri ve dosyaların özelliklerini değerlendirmek için; Örnekte, komutu çalıştırıyorsunuztest -w /home/durrantm
  • []parantez içindeki bir ifadeye benzemek için zorunlu son bir argümana sahip olan, aynı standartlaştırılmış, bu komutun bir diğer adıdır ; kanmayın, hala sadece bir komut (sisteminizde bir dosya olduğunu bile bulabilirsiniz /bin/[)
  • [[Test komutu bazı kabuklara yerleştirilmiş genişletilmiş bir versiyonudur, ancak aynı POSIX standardının bir parçası değildir; Burada kullanmadığınız ilave seçenekler içerir.

Koşullu ifadeler:

  • &&(Operatör burada standart ) iki komut değerlendirilmesi ve (gerçek temsil eder) 0 döndürerek, mantıksal VE işlemini gerçekleştirir, bu dönüş 0, her iki; yalnızca ilk komutu sıfır döndürdüğünde ikinci komutu değerlendirir, böylece basit bir koşullu olarak kullanılabilir
  • if ... then ... fi(Yapı burada standart ) "gerçek" yargılama aynı yöntem kullanılır, ancak tabloların bileşiği, liste sağlar thenyerine bir sağladığı tek bir komut, daha maddesi &&kısa devre ve sağlar elifve elseyazma zor maddeleri, sadece &&ve kullanarak ||. Bir ifdeyimde durumun etrafında hiçbir parantez olmadığını unutmayın .

Bu nedenle, aşağıdakilerin tümü eşit derecede taşınabilir ve tamamen eşdeğerdir, örneğinizin görünümleri:

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

Aşağıdakiler de eşdeğer olmakla birlikte, standart olmayan doğası nedeniyle daha az taşınabilir olsa da [[:

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi

Evet if .... fi kısmını 1 soru yapmak için kaldırdım.
Michael Durrant

7

Taşınabilirlik için, test/ kullanın [. Ancak taşınabilirliğe gerek duymuyorsanız, kendinizin ve diğerlerinin senaryoyu okuduğunun akıl sağlığı için [[. :)

Ayrıca bakınız What is the difference between test, [ and [[ ?de BashFAQ .


7

Bourne benzeri dünya dışında taşınabilirlik istiyorsanız, o zaman:

test -w /home/durrantm && echo writable

en taşınabilir. Bourne kabukları cshve rcaileleriyle çalışır.

test -w /home/durrantm && echo "writable"

çıktılayacaktır "writable"yerine writablekabuklarında rcailesi ( rc, es, akanga, nerede "özel değil).

[ -w /home/durrantm ] && echo writable

kabuklarında işe yaramaz cshya rcbir yok sistemlerde ailelerde [komutunu $PATH(bazılarına sahip bilinmektedir testonun değil [diğer adı).

if [ -w /home/durrantm ]; then echo writabe; fi

sadece Bourne ailesinin kabukları içinde çalışır.

[[ -w /home/durrantm ]] && echo writable

sadece ksh(kaynaklandığı yerde) zshve bash(Bourne ailesindeki her 3) de çalışır.

Hiçbiri, fishihtiyacınız olan kabukta işe yaramaz :

[ -w /home/durrantm ]; and echo writable

veya:

if [ -w /home/durrantm ]; echo writable; end

0

Seçim yapmak için ya if foo; then bar; fida seçmemdeki en önemli neden foo && bar, tüm komutun çıkış durumunun önemli olup olmadığıdır.

karşılaştırmak:

#!/bin/sh
set -e
foo && bar
do_baz

ile:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

Onların da aynı şeyi yaptığını düşünebilirsiniz; ancak foobaşarısız olursa (veya bakış açınıza bağlı olarak yanlışsa), ilk örnekte do_baz çalıştırılmaz, komut dosyası çıkacağı için ... set -eHerhangi bir komut yanlış bir durum döndürürse kabuğa hemen çıkması talimatını verir. Gibi şeyler yapıyorsanız çok yararlı:

cd /some/directory
rm -rf *

cdHerhangi bir nedenle başarısız olursa , komut dosyasının çalışmaya devam etmesini istemezsiniz .


1
Hiçbir başarısızlık foo, her iki durumda da senaryoyu iptal etmeyecektir. Bunun için özel bir durum set -ebazılarının sola (komut bir koşul olarak değerlendirildiğinde (&& / || veya eğer / ise /) / elsif ... koşullar kadar bir başarısız. barHer iki durumda da kabuk çıkmak istiyorum.
Stéphane Chazelas

2
İster cd /some/directory && rm -rf -- *veya cd /some/directory || exit; rm -rf -- *(hala gizli dosyaları silmez). Şahsen ben set -edoğru kod yazmak için çaba sarf etmemek için bir bahane olarak kullanma fikrini sevmiyorum .
Stéphane Chazelas
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.