Bir kabuk komut dosyasında Boole değişkenlerini nasıl bildirebilir ve kullanabilirim?


979

Aşağıdaki sözdizimini kullanarak bir kabuk komut dosyasında bir Boolean değişkeni bildirmeye çalıştım:

variable=$false

variable=$true

Bu doğru mu? Ayrıca, bu değişkeni güncellemek istersem aynı sözdizimini kullanır mıydım? Son olarak, aşağıdaki Boole değişkenlerini ifade olarak kullanmak için aşağıdaki sözdizimi doğru mu?

if [ $variable ]

if [ !$variable ]

73
DİKKAT! trueve falseen snippet'lerinde bağlamında aşağıda sadece düz dizeleri vardır değilbash built-ins !!! Lütfen aşağıdaki Mike Holt'un cevabını okuyun. (Bu, çok oylanan ve kabul edilen bir yanıtın
IMHO'nun

7
@mjv Bu soru (ve Miku'nun cevabı) üzerindeki karışıklığın çoğu, Miku'nun, Miku'nun cevabının bash yerleşik olarak adlandırılmasını nasıl içerdiğini açıklayan birkaç yorum gönderildikten sonra bir noktada cevabını revize etmesinden kaynaklanıyordutrue . Miku'nun orijinal cevabının gerçekten trueyerleşik olarak adlandırdığı ortaya çıktı, ancak gözden geçirilmiş cevap vermedi. Bu, Miku'nun kodunun nasıl çalıştığı hakkında yorumların yanlış görünmesine neden oldu. Miku'nun cevabı o zamandan beri hem orijinal hem de gözden geçirilmiş kodu açıkça göstermek için düzenlendi. Umarım bu karışıklığı bir kez ve herkes için dinlendirir.
Mike Holt

2
[ true ] && echo yes, true is trueve (upppsss) [ false ] && echo yes, false is also true. / bin / true ve / bin / false bir dönüş kodu $ verir? karşılaştırma için olmayan işlevler için.
fcm

Var doğrudan ayarlanırsa variable=something, ayarlanmamışsa variable=yanlış [[ $variable ]] && echo true || echo falseve ters olur[[ ! $variable ]] && echo false || echo true
Ivan

Yanıtlar:


1201

Revize Cevap (12 Şub 2014)

the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi

Orijinal Yanıt

Uyarılar: https://stackoverflow.com/a/21210966/89391

the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
    echo 'Be careful not to fall off!'
fi

Kimden: Bash'de boole değişkenlerini kullanma

Orijinal cevabın buraya dahil edilmesinin nedeni, 12 Şubat 2014'teki revizyondan önceki yorumların sadece orijinal cevapla ilgili olması ve gözden geçirilmiş cevapla ilişkili olduğunda yorumların çoğunun yanlış olmasıdır. Örneğin, Dennis Williamson'ın true2 Haziran 2010'da bash yerleşimi hakkındaki yorumu , sadece orijinal cevap için geçerlidir, gözden geçirilmiş değil.


37
Neler olduğunu açıklamak için: ififade, Bash yerleşkesi olan değişkenin içeriğini yürütüyor true. Herhangi bir komut, değişkenin değeri olarak ayarlanabilir ve çıkış değeri değerlendirilir.
sonraki duyuruya kadar duraklatıldı.

7
@pms "-o" ve "-a" işleçleri yalnızca "test" komutu içindir (aka "[]"). Bunun yerine, bu "test" olmadan "if + command" olur. ("İf grep foo dosyası; sonra ..." gibi.) Yani, normal &&ve ||işleçleri kullanın : # t1=true; t2=true; f1=false;# if $t1 || $f1; then echo is_true ; else echo is_false; fi; (t1 = true olduğundan "true " değerini döndürür) # if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi (t2 = true olduğundan "true" değerini döndürür) . Yine, bu SADECE çalışır çünkü "true" / "false" bash yapılıdır (true / false döndürür). Var bir cmd (yani, doğru veya yanlış) olmadığı sürece "$ $ var ..." kullanamazsınız
michael

14
-1, benim cevaba bakınız bir açıklama.
Dennis

3
Burada bir sürü yanlış bilgi var. / bin / true etkin bir şekilde kullanılmıyor. Dennis'in cevabına bakınız.
ajk

1
Bu kod aynı değildir ve bağlantılı makale ile aynı şekilde çalışmaz. Bağlı kod, bir değişkeni saklanan ada göre bir programı çağırır, ancak bu yanıttaki kod yalnızca dize karşılaştırmasıdır.
Quolonel Soruları

794

TL; DR

bool=true

if [ "$bool" = true ]

Miku'nun ( orijinal ) cevabı ile ilgili sorunlar

Ben do not kabul cevabı tavsiye 1 . Sözdizimi güzel, ancak bazı kusurları var.

Diyelim ki aşağıdaki durumumuz var.

if $var; then
  echo 'Muahahaha!'
fi

Aşağıdaki durumlarda 2 , bu koşul true olarak değerlendirilir ve iç içe komutu yürütür.

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".        Case 2
var=    #                              Case 3
unset var  #                           Case 4
var='<some valid command>'  #          Case 5

Genellikle varbu örnekte "Boolean" değişkeniniz açıkça true olarak ayarlandığında koşulunuzun true olarak değerlendirilmesini istersiniz . Diğer tüm vakalar tehlikeli yanıltıcıdır!

Son durum (# 5), özellikle değişkente bulunan komutu yürüteceği için yaramazdır (bu nedenle koşul, geçerli komutlar 3, 4 için true olarak değerlendirilir ).

İşte zararsız bir örnek:

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

Değişkenlerinizi alıntılamak daha güvenlidir, örn if "$var"; then. Yukarıdaki durumlarda, komutun bulunmadığına dair bir uyarı almalısınız. Ancak yine de daha iyisini yapabiliriz (aşağıdaki önerilerime bakın).

Ayrıca Mike Holt'un Miku'nun orijinal cevabına ilişkin açıklamasına bakın.

Hbar'ın cevabı ile ilgili sorunlar

Bu yaklaşımın beklenmedik davranışları da vardır.

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

Yukarıdaki koşulun yanlış olarak değerlendirilmesini beklersiniz, böylece iç içe ifadeyi asla çalıştırmazsınız. Sürpriz!

Değeri ( "false") tırnak içine almak, ( "$var") değişkenini tırnak içine almak testveya [[yerine veya yerine kullanmak [fark yaratmaz.

Ne do tavsiye:

İşte size "Booleans" inizi kontrol etmenizi tavsiye ettiğim yollar. Beklendiği gibi çalışırlar.

bool=true

if [ "$bool" = true ]; then
if [ "$bool" = "true" ]; then

if [[ "$bool" = true ]]; then
if [[ "$bool" = "true" ]]; then
if [[ "$bool" == true ]]; then
if [[ "$bool" == "true" ]]; then

if test "$bool" = true; then
if test "$bool" = "true"; then

Hepsi hemen hemen eşdeğerdir. Diğer cevaplar yaklaşımlar göre biraz daha fazla tuş vuruşlarını yazmanız gerekecek 5 , ancak kod daha defansif olacak.


Dipnotlar

  1. Miku'nun cevabı o zamandan beri düzenlendi ve artık (bilinen) kusurlar içermiyor.
  2. Kapsamlı bir liste değil.
  3. Bu bağlamda geçerli bir komut, var olan bir komut anlamına gelir. Komutun doğru veya yanlış kullanılması önemli değildir. Örneğin man woman, böyle bir kılavuz sayfa olmasa bile geçerli bir komut olarak kabul edilir.
  4. Geçersiz (var olmayan) komutlar için Bash, komutun bulunmadığından şikayet eder.
  5. Uzunluğu önemsiyorsanız, ilk öneri en kısa olanıdır.

8
Kullanımı ==ile [veya testtaşınabilir değildir. Taşınabilirliği göz önünde bulundurmanın tek avantajı var [/ testvar [[, bağlı kalın =.
chepner

2
@Scott Bence bash ile karşılaştırıldığında aklı başında bir senaryo dili olan birincil kabuk olarak balığı kullanıyorum .
Dennis

1
Evet, yorumlarda bu gizli şaka için herhangi bir takdir bulamadım, bu yüzden işaret etmek zorundaydım =)
Kranach

5
Benim için kavramsal olarak bool = "true" kullanıp kullanmadığımı anlamak daha kolay. O zaman bu sadece bir dize ve bazı özel değer veya yerleşik değil açıktır.
wisbucky

1
@dolmen kesinlikle, girdiyi kontrol ederken girdiyi değerlendirmek riskli değildir, ancak yine de kolayca önlenebilirse kaçınılması gereken kötü bir uygulama olduğunu düşünüyorum. Sadece eski stili görmüş ve kullanan biri, beklenmedik davranışlara neden olabilecek kusurlarını bilmeyebilir.
Dennis

175

Burada Bash yerleşkesi trueve daha spesifik olarak Bash'in parantez içindeki ifadeleri nasıl genişlettiği ve yorumladığı hakkında bazı yanlış anlaşılmalar var gibi görünüyor .

Miku'nun cevabındaki kodun , Bash yerleşkesi trueile ne /bin/truede truekomutanın başka bir lezzeti ile hiçbir ilgisi yoktur . Bu durumda, truebasit bir karakter dizesinden başka bir şey değildir ve truene değişken ataması ne de koşullu ifadenin değerlendirilmesi ile hiçbir zaman komuta / yerleşik'e çağrı yapılmaz .

Aşağıdaki kod, miku'nun cevabındaki kodla işlevsel olarak aynıdır:

the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
    echo 'Be careful not to fall off!'
fi

Buradaki tek fark, karşılaştırılan dört karakterin 't', 'r', 'u' ve 'e' yerine 'y', 'e', ​​'a' ve 'h' olmasıdır. Bu kadar. yeahBash tokenini ayrıştırdığında herhangi bir özel işlem veya miku örneği olarak adlandırılan bir komut çağırma girişimi yoktur true. Bu sadece bir ip ve tamamen keyfi bir ip.

Güncelleme (2014-02-19): Miku'nun cevabındaki bağlantıyı takip ettikten sonra, şimdi bazı karışıklıkların nereden geldiğini görüyorum. Miku'nun yanıtı tek parantez kullanır, ancak bağlandığı kod snippet'i parantez kullanmaz. Bu sadece:

the_world_is_flat=true
if $the_world_is_flat; then
  echo 'Be careful not to fall off!'
fi

Her iki kod parçacığı da aynı şekilde davranacaktır , ancak parantezler kaputun altında neler olup bittiğini tamamen değiştirecektir.

Bash'in her durumda yaptığı şey:

Parantez yok:

  1. Değişkeni $the_world_is_flatdizeye genişletin "true".
  2. Dizeyi "true"komut olarak ayrıştırma girişimi .
  3. trueKomutu bulun ve çalıştırın (yerleşik veya /bin/trueBash sürümüne bağlı olarak).
  4. trueKomutun çıkış kodunu (her zaman 0 olan) 0 ile karşılaştırın. Çoğu kabukta, 0'lık bir çıkış kodunun başarıyı ve diğer her şeyin başarısızlığı gösterdiğini hatırlayın.
  5. Çıkış kodu 0 (başarılı) olduğundan, ififadenin thenyan tümcesini yürütün

Parantez:

  1. Değişkeni $the_world_is_flatdizeye genişletin "true".
  2. Şu anda tamamen genişleyen koşullu ifadeyi, biçimdedir string1 = string2. =Operatör Bash'in olan dizge karşılaştırma operatörü. Yani...
  3. Üzerinde bir dize karşılaştırma yapın "true"ve "true".
  4. Evet, iki dize aynıydı, bu yüzden koşulun değeri doğrudur.
  5. Yürütme ififadenin thenmaddesini.

Köşeli parantez içermeyen kod çalışır, çünkü truekomut, başarıyı gösteren 0 çıkış kodunu döndürür. Köşeli ayraçlı kod çalışır, çünkü değeri, $the_world_is_flatöğesinin truesağ tarafındaki dize hazır bilgisi ile aynıdır =.

Sadece noktayı eve götürmek için aşağıdaki iki kod snippet'ini düşünün:

Bu kod (kök ayrıcalıklarıyla çalıştırılırsa) bilgisayarınızı yeniden başlatır:

var=reboot
if $var; then
  echo 'Muahahaha! You are going down!'
fi

Bu kod sadece "İyi deneme" yazdırır. Reboot komutu çağrılmaz.

var=reboot
if [ $var ]; then
  echo 'Nice try.'
fi

Güncelleme (2014-04-14)= ve ==: AFAIK arasındaki farkla ilgili yorumlarda soruyu cevaplamak için hiçbir fark yoktur. ==Operatör için Bash özgü eşanlamlı olduğunu =ve çok gördüm gibi, hepsi bağlamlarda aynı çalışır.

Ancak, özellikle veya testlerde kullanılan =ve ==dize karşılaştırma işleçleri hakkında konuştuğumu unutmayın . Ben bunu önermiyorum ve bash her yerde değiştirilebilir .[ ][[ ]]===

Örneğin, ( ==örneğin var=="foo"teknik olarak bunu yapabilirsiniz , ancak değeri varolacaktır "=foo", çünkü Bash ==burada bir operatör görmediği için bir =(atama) operatörü görüyor , ardından gerçek değeri ="foo"olur "=foo").

Ayrıca her ne kadar =ve ==birbirleriyle değiştirilebilir bu testler iş nasıl, sen akılda tutmalı yok içinizde kullanmaya bağlı olarak değişir [ ]ya da [[ ]]ve ayrıca üzerinde işlenenler cinsindendir olsun veya olmasın. Daha bu konuda okumak içinde olabilir 7.3 Diğer Karşılaştırma Operatörleri: İleri Bash komut dosyası Kılavuzu (tartışmasına aşağı kaydırın =ve ==).


Parantezsiz yaklaşım, temiz, net (imo) tek gömlekler gibi yazmanıza izin verme avantajına da sahiptir$the_world_is_flat && echo "you are in flatland!"
ajk

9
Doğru. Rağmen, ben her iki yaklaşım için (veya karşı) savunmuyorum. Burada oylanan bazı yanlış bilgileri silmek istedim, böylece daha sonra bu konuya rastlayan insanlar, bunların nasıl çalıştığına dair bir dizi yanlış anlama ile uzaklaşmayacaklar.
Mike Holt

1
Karışıklığın nedeni, miku'nun orijinal cevabının 4 yıl boyunca durmasıydı. Yerleşikliğe tüm referanslar trueorijinal cevap ile ilgili olarak yapılmıştır. (12 Şubat 2014 tarihinde revize edilen cevap miku tarafından gönderilmemiştir.) Cevabı hem orijinal hem de revize edilecek şekilde düzenledim. Sonra insanların yorumları mantıklı.
wisbucky

1
Burada sunulan cevapları okurken, gerçek olanı kullanmak gibi bir şey olmadığı izlenimini edindim true. Bir yolu var mı? bashHayatlarını biraz daha kolay hale getirmek için bazı yapıştırıcıların karıştırılmasına yardımcı olmak için bu cevabı görüntüleyen dilleri sıkılaştırmaya alışkın olan birçok programcıdan ===, dizelerin ve "boolean" ın aslında değiştirilebilir olmaması için bir operatör isteyebileceğinden şüpheleniyorum . Onlar sadece 0 ve 1 ve kullanım tutması gerektiğini (( $maybeIAmTrue ))önerildiği üzere Quolonel Soru 'ın cevabı ?
SeldomNeedy

2
SeldomNeedy'nin yorumuna hitap etmek için, evet, gerçek true, truekendi başına bir değere sahip olmadığından , bir değişkeni karşılaştırmak için gerçek olarak değil, genel olarak kullanabilirsiniz . Tüm yaptığı, çıkış durumunu 0başarılı olarak belirten olarak ayarlamaktır . Bunun aslında "null command" (null komutu) veya ile eşdeğer olduğunu belirtmek gerekir :. Bildiğim kadarıyla kullanma gibi 0ve 1ben Boolean ihtiyacım bugünlerde tüm script'lerime ne olduğunu. Ve değerlendirmek (( ))yerine operatörü kullanıyorum [[ ]]. Örneğin, eğer flag=0yapabilirsem, yapabilirimif (( flag )); then ...
Mike Holt

57

Aritmetik ifadeler kullanın.

#!/bin/bash

false=0
true=1

((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true

Çıktı:

doğru
yanlış değil


3
artıları: (1.) davranış C'nin bools'u ele alma şekline benzer, (2.) sözdizimi çok özlü / minimaldir (sağ değişken ve '=' veya '==' gibi operatörler gerektirmez), (3 .) <sübjektif> benim için uzun soluklu bir açıklama olmadan ne olduğunu anlıyorum ... her ikisi de uzun soluklu açıklamalar gerektiriyor gibi görünen Miku ve Dennis'in cevaplarının aksine </subjective>
Trevor Boyd Smith

3
@TrevorBoydSmith Neden sadece "artıları: her şey, eksileri: hiçbir şey" demedin. Uzun vadede klavyenizdeki ve monitörünüzde amortisman maliyetlerinden tasarruf edersiniz.
Quolonel Soruları

4
Tek gömlekler gibi etkileşimli kullanım için, sonradan bir boşluk bıraktığınızdan emin olun !, aksi takdirde geçmiş genişlemesi yapar. ((! foo))çalışıyor, öyle ! ((foo)). Bu çözümü seviyorum, BTW. Son olarak, boole değişkenleri yapmanın kısa bir yolu. ((foo || bar))beklendiği gibi çalışır.
Peter Cordes

5
(())beklemediğim değişkenleri özyinelemeli olarak genişletir. foo=bar; bar=baz; ((foo)) && echo echohiçbir şey basmıyor, ama bu doğru baz=1. Böylece destekleyerek foo=trueve foo=false0 veya 1 yaparak yapabilirsiniz true=1.
Peter Cordes

2
@quolonel çok yardımcı kaynak için teşekkür ederim. Tabii ki anlayışım sınırlı - alan ne olursa olsun tüm anlayışta sınırlı olmak insan doğasıdır. Ancak, bana bu ifadelerden hangisinin sizi bu konu hakkındaki anlayışımın eksik olduğu varsayımına götürdüğünü söyler misiniz?
Hubert Grzeskowiak

34

Uzun lafın kısası:

Bash'de Boole yok

Bash karşılaştırma ve koşullar açısından Boole ifadelerine sahiptir. Bununla birlikte, Bash'de beyan edebileceğiniz ve karşılaştırabileceğiniz şey dizeler ve sayılardır. Bu kadar.

Her yerde gördüğünüz trueveya falseBash, bir dize veya sadece çıkış kodu için kullanılan bir komut / yerleşik ya bu.

Bu sözdizimi ...

if true; then ...

aslında ...

if COMMAND; then ...

Komut, çıkış kodu 0'ı döndürdüğünde trueve falseBash yerleşikleri ve bazen de karşılık gelen çıkış kodunu döndürmekten başka bir şey yapmayan bağımsız programlardır.

Yukarıdaki koşul şuna eşdeğerdir:

COMMAND && ...

Köşeli parantez veya testkomut kullanırken, bu yapının çıkış koduna güvenirsiniz. Unutmayın [ ]ve [[ ]]sadece diğerleri gibi komutlar / yerleşikler. Yani ...

if [[ 1 == 1 ]]; then echo yes; fi

karşılık gelir

if COMMAND; then echo yes; fi

ve COMMANDişte burada[[ 1 == 1 ]]

if..then..fiYapı sadece sözdizimsel şeker olduğunu. Her zaman aynı efekt için çift amperle ayrılmış komutları çalıştırabilirsiniz:

[[ 1 == 1 ]] && echo yes

Bu test yapılarını kullanırken trueve kullanırken falseaslında sadece dizeyi "true"veya "false"test komutunu geçersiniz. İşte bir örnek:

İster inanın ister inanmayın, ancak bu koşulların hepsi aynı sonucu veriyor :

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL; DR; her zaman dizelerle veya sayılarla karşılaştır

Bunu gelecekteki okuyucular için netleştirmek için, her zaman tırnak işareti kullanmanızı tavsiye ederim trueve false:

YAPMAK

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

DO dEĞİL

if [ ... ]; then ...  # Always use double square brackets in bash!
if [[ "${var}" ]]; then ...  # This is not as clear or searchable as -n
if [[ "${var}" != true ]]; then ...  # Creates impression of Booleans
if [[ "${var}" -eq "true" ]]; then ...  # `-eq` is for numbers and doesn't read as easy as `==`

Olabilir

if [[ "${var}" != "true" ]]; then ...  # Creates impression of Booleans. It can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".

Kullanmayı Tve Fbunların gerçek boole değerleri olmadığını açıkça belirtmeyi tercih ediyorum .
phk

1
"Her zaman bash'de çift parantez kullanın" ile anlaşamıyorum. Aslında yazdığım hemen hemen tüm komut dosyalarında, desen eşleştirme yapmam gerektiğinde tek parantez kullanıyorum. Bence kişi [(yani test) arasındaki farkı anlamalı [[ve ihtiyacı için uygun olanı kullanmalıdır.
Weijun Zhou

@ WeijunZhou zihin hangi durumlarda tek parantez daha iyidir ayrıntılı?
Hubert Grzeskowiak

Daha kişisel bir zevk, sadece "Her zaman bash içinde çift köşeli parantez kullanın" demenin çok cesur olduğunu görüyorum. Ama kullandığım bazı kenar durumlar var. Tek parantez, testin kendisini bir var. Çok basitleştirilmiş bir örnek olarakif ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Weijun Zhou

@ WeijunZhou Örneğiniz tek köşeli parantezlere karşı güçlü bir argüman. Kodun anlaşılmasını çok daha zorlaştırır ve pencereyi hatalara açık olarak açar. Çift parantez daha katıdır ve daha temiz kodları teşvik eder.
Hubert Grzeskowiak

18

Uzun zaman önce, sahip olduğumuz her şey olduğunda sh, Booleans, herhangi bir argüman olmadan çalıştırıldığında yanlış bir çıkış durumu döndüren testprogramın bir kuralına dayanarak ele alındı test.

Bu, yanlış olarak ayarlanmamış bir değişkeni ve herhangi bir değere doğru olarak ayarlanmış bir değişkeni düşünmeyi sağlar. Bugün, testBash için bir yerleşiktir ve tek karakterli takma adı [(veya dolmen notları olarak eksik kabuklarda kullanmak için bir yürütülebilir dosya) tarafından bilinir :

FLAG="up or <set>"

if [ "$FLAG" ] ; then
    echo 'Is true'
else
    echo 'Is false'
fi

# Unset FLAG
#    also works
FLAG=

if [ "$FLAG" ] ; then
    echo 'Continues true'
else
    echo 'Turned false'
fi

Alıntı kuralları nedeniyle, senaryo yazarları [[taklit eden testancak daha güzel bir sözdizimine sahip olan bileşik komutu kullanmayı tercih ederler : boşluklu değişkenlerin alıntılanması gerekmez; garip önceliğe sahip &&ve ||mantıksal işleçler olarak kullanılabilir ve terim sayısında POSIX sınırlaması yoktur.

Örneğin, FLAG'ın ayarlandığını ve COUNT öğesinin 1'den büyük bir sayı olup olmadığını belirlemek için:

FLAG="u p"
COUNT=3

if [[ $FLAG  && $COUNT -gt '1' ]] ; then
    echo 'Flag up, count bigger than 1'
else
    echo 'Nope'
fi

Boşluklar, sıfır uzunluklu dizeler ve boş değişkenler gerektiğinde ve ayrıca komut dosyanızın birkaç kabukla çalışması gerektiğinde bu şeyler kafa karıştırıcı olabilir .


3
[sadece içerideki bir takma ad değildir bash. Bu takma ad ayrıca bir ikili dosya (veya işaret eden bir bağlantı) olarak bulunur ve çıplak olarak kullanılabilir sh. Kontrol edin ls -l /usr/bin/\[. İle bash/ zshyerine kullanması gereken [[bir gerçek saf iç ve çok daha güçlüdür.
dolmen

1
@dolmen [ve testayrıca Bash kılavuz sayfasına göre bir Bash SHELL BUILTIN COMMAND, bu nedenle performansta bir sorun olmamalıdır. Örneğin Dash ile aynı şey. (/ bin / sh yalnızca / bin / dash için bir sembolik bağlantı olabilir). Yürütülebilir dosyayı kullanmak için tam yol yani kullanmanız gerekir /usr/bin/\[.
jarno

12

Bir kabuk komut dosyasında Boole değişkenlerini nasıl bildirebilir ve kullanabilirim?

Diğer birçok programlama dilinden farklı olarak Bash, değişkenlerini "türe" göre ayırmaz. [1]

Cevap çok açık. Bash'de herhangi bir Boolean değişkeni yoktur .

Ancak:

Bir declare deyimi kullanarak değer atamasını değişkenlerle sınırlayabiliriz. [2]

#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}

# Same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"

rSeçeneğini declareve readonlydeğişkenler açık olarak bu duruma kullanılır salt okunur . Umarım amaç açıktır.


1
Neden sadece yapmıyorsun declare -ir false=0 true=1? Dizi kullanmanın avantajı nedir?
Benjamin W.

@BenjaminW. Sadece rseçenek ve readonlykomuttan bahsetmek istedim . Komut dosyalarında önerdiğin gibi
yapardım

belki bir şey özledim ama neden bu şekilde ilan doğru ve yanlış dolar işareti kullanmak dont? $ true $ false
qodeninja

Kelimenin tam anlamıyla sadece cevabımı kopyalayıp daha da kötüleştiriyor.
Quolonel Soruları

@QuolonelQuestions Bash değişkenler değildir yazılan dolayısıyla söyleyerek hiçbir nokta yoktur, declare and use boolean variablesBiz sadece, birden fazla yolla, mimik içinde / değişken bir olduğunu varsayalım olabilir türü . Cevabınızda hiçbir yerde bahsetmedim.
sjsam

10

Bir Boole'yi taklit etmek ve gelecekteki okuyucular için bir tuzak bırakmak yerine, neden sadece doğru ve yanlıştan daha iyi bir değer kullanmıyorsunuz?

Örneğin:

build_state=success
if something-horrible; then
  build_state=failed
fi

if [[ "$build_state" == success ]]; then
  echo go home; you are done
else
  echo your head is on fire; run around in circles
fi

neden tamsayılar değil?
phil294

3
@Blauhirn çünkü tamsayı dillere bağlı olarak farklı kullanılır. Bazı diller ise 0hiç coerces falseve 1için true. Program çıkış kodları ile ilgili olarak (geçmişte bash kullanan) 0olumlu sonuç için ya da trueher şey negatif / hata veya false.
Hubert Grzeskowiak

7

POSIX (Taşınabilir İşletim Sistemi Arayüzü)

Burada taşınabilirlik olan kilit noktayı özlüyorum. Bu yüzden başlığımın içinde POSIX var .

Esasen, oylanan cevapların hepsi doğrudur, ancak Bash'e özgüdürler.

Temel olarak, sadece taşınabilirlik hakkında daha fazla bilgi eklemek istiyorum.


  1. [ve ]içindeki parantezler [ "$var" = true ]gerekli değildir ve bunları atlayabilir ve testkomutu doğrudan kullanabilirsiniz :

    test "$var" = true && yourCodeIfTrue || yourCodeIfFalse

    Önemli not: Yavaş yavaş kullanımdan kaldırıldığı ve birden fazla ifadeyi birleştirmesi daha zor olduğu için artık bunu önermiyorum .

  2. Bu kelimelerin trueve falsekabuk için ne anlama geldiğini hayal edin , kendiniz test edin:

    echo $(( true ))
    0
    echo $(( false ))
    1

    Ancak tırnak işaretleri kullanarak:

    echo $(( "true" ))
    bash: "true": syntax error: operand expected (error token is ""true"")
    sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""

    Aynısı - için de geçerli:

    echo $(( "false" ))

    Kabuk, bir dize dışında onu yorumlayamaz. Umarım tırnak işaretleri olmadan uygun anahtar kelimeyi ne kadar iyi kullandığına dair fikir edinirsiniz .

    Ama kimse önceki cevaplarda söylemedi.

  3. Ne anlama geliyor? Pek çok şey.

    • Boolean anahtar kelimelerine aslında sayı gibi davranılır, yani true= 0ve false= 1, sıfır olmayan tüm değerlerinfalse .

    • Sayı olarak ele alındığından, onlara da böyle davranmalısınız, yani değişken tanımladıysanız:

      var_bool=true
      echo "$var_bool"
       true

      bununla zıt bir değer oluşturabilirsiniz:

      var_bool=$(( 1 - $var_bool ))  # same as $(( ! $var_bool ))
      echo "$var_bool"
      1

    Kendiniz görebileceğiniz gibi, kabuk truedizgiyi ilk kez kullandığınızda yazdırır , ancak o zamandan beri , sırasıyla sırasıyla 0temsil trueveya 1temsil eden sayı ile çalışır false.


Son olarak, tüm bu bilgilerle ne yapmalısınız?

  • Birincisi, iyi bir alışkanlık 0yerine true; 1yerine false.

  • İkinci iyi alışkanlık, değişkenin sıfıra eşit olup olmadığını test etmektir:

    if [ "$var_bool" -eq 0 ]; then
         yourCodeIfTrue
    else
         yourCodeIfFalse
    fi

6

Sözdizimi ile ilgili olarak, bu Boole mantığını tutarlı ve güvenli bir şekilde yönetmek için kullandığım basit bir metodolojidir:

# Tests
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc

if [[ -n "${var}" ]] ; then
    echo 'true'
fi
if [[ -z "${var}" ]] ; then
    echo 'false'
fi

# Results
# var=        # false
# var=''      # false
# var=""      # false
# var=0       # true
# var=1       # true
# var="abc"   # true
# var=abc     # true

Değişken asla bildirilmezse cevap: # false

Bu nedenle, bir değişkeni true değerine ayarlamanın basit bir yolu (bu sözdizimi yöntemini kullanarak) var=1; tersine var='',.

Referans:

-n = Var dizesinin uzunluğu sıfırdan farklıysa doğrudur.

-z = Var dizesinin uzunluğu sıfır ise doğrudur.


5

Birçok programlama dilinde, Boolean türü aşağıdaki truegibi davranan 1ve falsedavranan bir tamsayı alt türüdür veya şu şekilde uygulanır 0:

Matematiksel olarak , Boole cebri tamsayı aritmetik modülo 2'yi andırır. Bu nedenle, bir dil yerel Boolean tipi sağlamazsa, en doğal ve verimli çözüm tamsayıları kullanmaktır. Bu hemen hemen her dilde çalışır. Örneğin, Bash'te şunları yapabilirsiniz:

# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false

adam bash :

((İfade))

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


5

Bill Parker oylanacak , çünkü tanımları normal kod sözleşmesinden geri alınmıştır. Normalde true, 0 olarak ve false sıfırdan farklı olarak tanımlanır. 1, 9999 ve -1 gibi yanlış için çalışacaktır. İşlev döndürme değerleri ile aynıdır - 0 başarıdır ve sıfır olmayan her şey başarısızlıktır. Maalesef, oy vermek veya doğrudan ona cevap vermek için henüz sokak güvenilirliğim yok.

Bash şimdi çift parantezleri tek parantez yerine alışkanlık olarak kullanmanızı önerir ve Mike Holt'un verdiği bağlantı nasıl çalıştıklarındaki farklılıkları açıklar. 7.3. Diğer Karşılaştırma Operatörleri

Birincisi, -eqsayısal bir operatör, yani

#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

bir tamsayı ifadesi bekleyen bir hata bildirimi verir. Tamsayı değeri olmadığından bu, her iki parametre için de geçerlidir. Yine de, etrafına çift parantez koyarsak, bir hata bildirimi yayınlamaz, ancak yanlış bir değer verir (olası permütasyonların% 50'sinde). [[0 -eq true]] = başarı için değil, aynı zamanda [[0 -eq false]] = başarı için de değerlendirir (ki bu yanlıştır (hmmm .... bu yerleşikliğin sayısal bir değer olmasına ne dersiniz?).

#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then

Koşulun yanlış çıktı verecek başka permütasyonları da vardır. Temel olarak, bir değişkeni sayısal bir değere ayarlayan ve onu doğru / yanlış bir yerleşik ile karşılaştıran veya bir değişkeni doğru / yanlış bir yerleşik ile ayarlayan ve bunu sayısal bir değerle karşılaştıran her şey (yukarıda listelenen hata koşulu dışında). Ayrıca, bir değişkeni true / false yerleşkesine ayarlayan ve kullanarak karşılaştırma yapan her şey -eq. Bu nedenle -eqBoole karşılaştırmaları için kaçının ve Boolean karşılaştırmaları için sayısal değerler kullanmaktan kaçının. Geçersiz sonuçlar verecek permütasyonların bir özeti:

# With variable set as an integer and evaluating to true/false
# *** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

# With variable set as an integer and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then


# With variable set as an true/false builtin and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then

Şimdi, neyin işe yaradığına. Hem karşılaştırmanız hem de değerlendirmeleriniz için true / false yerleşiklerini kullanın (Mike Hunt'un belirttiği gibi, bunları tırnak içine almayın). Sonra tek veya çift eşit işareti (= veya ==) ve tek veya çift parantez ([] veya [[]]) kullanın. Şahsen, çifte eşittir işaretini seviyorum, çünkü bana diğer programlama dillerindeki mantıksal karşılaştırmaları hatırlatıyor ve sadece yazmayı sevdiğim için çift tırnak. Yani bu işler:

# With variable set as an integer and evaluating to true/false
# *** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then

İşte aldın.


2
true/ falseGömmeler burada kullanılmaz özellikle de, (bazı editörler vurgulayarak sözdizimi ima edebilecek görmezden) […]Burada basit bir dize (bir parametre olarak verilir biri olarak düşünmek durumlarda [komuta).
phk

Şimdi sende var.
Peter Mortensen

4

Bulgularım ve önerim diğer gönderilerden biraz farklı. "Booleans" temelde herhangi bir "normal" dilde olduğu gibi "çember atlama" önerilen olmadan kullanabilirsiniz bulundu ...

Herhangi bir []açık veya dize karşılaştırmalarına gerek yok ... Birden fazla Linux dağıtımı denedim. Bash, Dash ve BusyBox'ı test ettim . Sonuçlar hep aynıydı. En çok oy alan orijinal yayınların neden bahsettiğinden emin değilim. Belki zaman değişti ve hepsi bu kadar mı?

Bir değişkeni olarak ayarlarsanız true, daha sonra bir koşul içinde "olumlu" olarak değerlendirilir. Bunu olarak ayarlayın falseve "negatif" olarak değerlendirilir. Çok basit! Tek uyarı, tanımsız bir değişkenin de gerçek gibi değerlendirilmesidir ! Bunun tersini yapması iyi olurdu (çoğu dilde olduğu gibi), ancak bu hile - sadece boolean'larınızı doğru veya yanlış olarak başlatmanız gerekir .

Neden bu şekilde çalışıyor? Bu cevap iki kattır. A) bir kabuktaki true / false gerçekten "hata yok" vs "hata" anlamına gelir (yani 0 - başka bir şey). B) true / false değerler değil - kabuk betiğindeki ifadelerdir ! İkinci nokta ile ilgili olarak, kendi başına trueveya falsebir satırda yürütmek , içinde bulunduğunuz blok için dönüş değerini bu değere ayarlar, yani false"hata ile karşılaşıldı" ifadesi, burada doğru "temizlenir". Bir değişkene atama ile kullanmak bunu değişkene "döndürür". Bir tanımlanmamış değişken gibi değerlendirir trueşartlı bu eşit 0 ya da "hayır hata karşılaşılan" ni temsil ettiği.

Aşağıdaki örnek Bash çizgileri ve sonuçlarına bakın. Onaylamak istiyorsanız kendiniz test edin ...

#!/bin/sh

# Not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

Verim

when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false

1

İşte benim için çalışan basit bir örnek:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi

1

İşte kısa süreli bir uygulama if true.

# Function to test if a variable is set to "true"
_if () {
    [ "${1}" == "true" ] && return 0
    [ "${1}" == "True" ] && return 0
    [ "${1}" == "Yes" ] && return 0
    return 1
}

örnek 1

my_boolean=true

_if ${my_boolean} && {
    echo "True Is True"
} || {
    echo "False Is False"
}

ÖRNEK 2

my_boolean=false
! _if ${my_boolean} && echo "Not True is True"

Evet, fonksiyonel ayrışma az takdir edilmektedir.
Peter Mortensen

1

Mevcut cevapları kafa karıştırıcı buldum.

Şahsen, sadece C gibi görünen ve çalışan bir şeye sahip olmak istiyorum.

Bu snippet, üretimde günde birçok kez çalışır:

snapshotEvents=true

if ($snapshotEvents)
then
    # Do stuff if true
fi

ve herkesi mutlu etmek için test ettim:

snapshotEvents=false

if !($snapshotEvents)
then
    # Do stuff if false
fi

Hangi de iyi çalıştı.

$snapshotEventsDeğişkenin değeri içeriğini değerlendirir. Yani ihtiyacınız var $.

Parantezlere gerçekten ihtiyacınız yok, sadece yararlı buluyorum.


2
Parantezleri kaldırdığınızda, bu tam olarak @ miku'nun en üstteki orijinal yanıtıdır.
dolmen

1
Parantez olmadan ifade değerlendirilmez.
will

@ evet olacak. () Lere ihtiyacınız yoktur.
phil294

1
@Blauhirn ... Merhaba, yorumlarımı Linux Mint / Ubuntu PC'de GNU Bash ile yaptım. Muhtemelen teoride haklısın ()-s gerekli değil. Tek cevabım, denemek , Bash sürümüne, gerçek ifadeye veya içeriğe ve benzerlerine bağlı gibi görünüyor .
will

1

Miku'nun Dennis Williamson'ın değişkenin ayarlanmadığı durum hakkındaki endişelerini ele alan orijinal cevabı üzerinde bir gelişme :

the_world_is_flat=true

if ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

Ve değişkenin olup olmadığını test etmek için false:

if ! ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

Değişkende kötü içerik barındıran diğer durumlar hakkında, bu bir programa beslenen herhangi bir harici girişle ilgili bir sorundur.

Herhangi bir harici giriş, ona güvenmeden önce doğrulanmalıdır. Ancak bu doğrulama, bu girdi alındığında sadece bir kez yapılmalıdır.

Dennis Williamson'ın öne sürdüğü gibi değişkenin her kullanımı için programın performansını etkilemek zorunda değildir .


1

ShFlags kullanabilirsiniz .

Size aşağıdakileri tanımlama seçeneği sunar: DEFINE_bool

Misal:

DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");

Komut satırından şunları tanımlayabilirsiniz:

sh script.sh --bigmenu
sh script.sh --nobigmenu # False

GFlags bu cevapta bir anlam ifade etmiyor - bir C ++ kütüphanesi. Kabuk komut dosyalarında doğrudan kullanılamaz.
Jonathan Cross

GFlags'ın bir bağlantı noktası olan shFlags'a yanıt güncellendi.
gogasca

0

Bu, Bash'te "Boolean" değerlerini test etmenin farklı yolları hakkında bir hız testidir:

#!/bin/bash
rounds=100000

b=true # For true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done

b=x; # Or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done

b=1 # Or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done

Gibi bir şey basar

true is a shell builtin
true is /bin/true

real    0m0,815s
user    0m0,767s
sys     0m0,029s

real    0m0,562s
user    0m0,509s
sys     0m0,022s

real    0m0,829s
user    0m0,782s
sys     0m0,008s

real    0m0,782s
user    0m0,730s
sys     0m0,015s

real    0m0,402s
user    0m0,391s
sys     0m0,006s

real    0m0,668s
user    0m0,633s
sys     0m0,008s

real    0m0,344s
user    0m0,311s
sys     0m0,016s

real    0m0,367s
user    0m0,347s
sys     0m0,017s

-2

Alternatif - bir işlev kullanın

is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"

Fonksiyonu tanımlamak daha az sezgiseldir, ancak dönüş değerini kontrol etmek çok kolaydır.


1
Bu, test edebileceğiniz bir değişken değil, sürekli bir işlevdir
jarno

@jarno Bir işlevin dönüş değerini test etmek, bir komut dosyası için bir değişkeni test etmekten farklı mıdır?
johnraff

Soru değişkenlerle ilgili.
jarno

Doğru, ancak bir kabuk betiğindeki kullanım aynı olurdu.
johnraff

-2

Bash gerçekten gibilerle sorunu karıştırır [, [[, ((, $((, vb

Hepsi birbirlerinin kod alanlarına davranıyor. Sanırım bu çoğunlukla tarihsel, Bash'ın shzaman zaman taklidi yapmak zorunda kaldı .

Çoğu zaman, sadece bir yöntem seçip yapıştırabilirim. Bu durumda, beyan etme eğilimindeyim (tercihen .gerçek komut dosya (lar) ımla birlikte içerebileceğim ortak bir kütüphane dosyasında ).

TRUE=1; FALSE=0

Daha sonra bu şekilde test etmek için ((... ))aritmetik işleci kullanabilirim.

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # Do stuff because the directory does exist
fi
  1. Disiplinli olmak zorundasınız. Kişisel testvarzorunluluk olarak belirlenebilir $TRUEveya $FALSEher zaman.

  2. In ((... ))komparatörlerinde, sen önceki gerekmez $daha okunaklı hale getirir.

  3. Kullanabilirim ((... ))çünkü $TRUE=1ve $FALSE=0, yani sayısal değerler.

  4. Dezavantajı $arada sırada kullanmak zorunda :

    testvar=$TRUE

    ki bu çok hoş değil.

Mükemmel bir çözüm değil, ama böyle bir teste ihtiyacım olan her durumu kapsıyor.


2
Sabitlerinizi salt okunur olarak bildirmelisiniz. Ayrıca lütfen değişkenleri kullanırken daima süslü parantez kullanın. Herkesin IMHO'ya bağlı kalması gereken bir toplantı. Bu çözümün büyük dezavantajı, cebirsel ifadeyi test bayrakları veya dize karşılaştırmalarıyla karıştıramamanızdır.
Hubert Grzeskowiak
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.