Bash [yanlış] ise; doğru döndürür


151

Bu hafta bash öğreniyor ve bir engelle karşılaştım.

#!/bin/sh

if [ false ]; then
    echo "True"
else
    echo "False"
fi

Durum aksini gösteriyor gibi görünse de bu her zaman True sonucunu verir. Parantezleri çıkarırsam []çalışır, ancak nedenini anlamıyorum.


3
İşte başlamanız için bir şey.
keyser

10
BTW, ile başlayan bir betik #!/bin/shbash betiği değil - POSIX sh betiği. Sisteminizdeki POSIX sh yorumlayıcısı bash tarafından sağlansa bile, bir grup uzantıyı kapatır. Bash komut dosyaları yazmak istiyorsanız, #!/bin/bashveya yerel olarak uygun eşdeğerini #!/usr/bin/env bashkullanın ( PATH'deki ilk bash yorumlayıcısını kullanmak için).
Charles Duffy

Bu da etkiler [[ false ]].
CMCDragonkai

Yanıtlar:


192

Çalıştırdığınız [(aka testkomutu çalışmıyor, argüman "false" ile) komutu false. "False" boş olmayan bir dize olduğundan, testkomut her zaman başarılı olur. Komutu gerçekten çalıştırmak için komutu bırakın [.

if false; then
   echo "True"
else
   echo "False"
fi

4
Yanlış bir emir, hatta bir dize olma fikri bana tuhaf geliyor, ama sanırım işe yarıyor. Teşekkürler.
tenmiles

31
bashBoolean veri türüne sahip olmadığı için true ve false değerini gösteren hiçbir anahtar kelime yoktur. ifDeyimi sadece kontroller bunu vermek komut başarılı veya başarısız olursa. testKomut bir ifade alır ve ifade doğruysa başarılı; boş olmayan bir dize, diğer programlama dillerinde olduğu gibi true olarak değerlendirilen bir ifadedir. falseher zaman başarısız olan bir komuttur. ( true
Benzeterek

2
if [[ false ]];de doğru döner. Olduğu gibi if [[ 0 ]];. Ve if [[ /usr/bin/false ]];bloğu da atlamaz. False veya 0 sıfırdan farklı olarak nasıl değerlendirilebilir? Kahretsin bu sinir bozucu. Önemli ise, OS X 10.8; Bash 3.
jww

7
falseBoole sabiti veya 0tamsayı değişmezi için hata yapmayın ; her ikisi de sadece sıradan dizelerdir. tire ile başlamayan herhangi bir dizenin [[ x ]]eşdeğeridir . yok herhangi herhangi bir bağlamda Boole sabitleri. Tamsayılar gibi görünüm böyle iç olarak işlem görmeleri Dizeler veya gibi operatörleri ile veya içeride . [[ -n x ]]xbash(( ... ))-eq-lt[[ ... ]]
Chepner

2
@ tbc0, elinizde bir şeylerin nasıl okunduğundan daha fazla endişe var. Değişkenler tamamen kontrolünüz altında olmayan bir kodla ayarlanırsa (veya harici olarak değiştirilebiliyorsa, olağandışı dosya adlarıyla veya başka bir şekilde olsun), if $predicatedüşman kodunu if [[ $predicate ]]yapamayacak bir şekilde yürütmek için kolayca kötüye kullanılabilir .
Charles Duffy

55

Bash için Hızlı Boole Astarı

ifİfadesi bağımsız değişken olarak bir komut alır (gibi &&, ||vs.). Komutun tamsayı sonuç kodu bir boole (0 / null = true, 1 / else = false) olarak yorumlanır.

testİfadesi bağımsız değişkenleri olarak operatörleri ve işlenen alır ve aynı biçimde bir sonuç kodunu if. Bir diğer adı testdeyimi ise [sıklıkla kullanılır, hangi ifdaha karmaşık karşılaştırmalar yapmak için.

trueVe falsetablolar hiçbir şey ve bir sonuç kodu döndürür (0 ve 1 sırasıyla). Böylece Bash'te boole değişmezleri olarak kullanılabilirler. Ancak ifadeleri dize olarak yorumlandıkları bir yere koyarsanız, sorun yaşarsınız. Senin durumunda:

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

Yani:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

Bu, echo '$foo'vs. gibi bir şey yapmaya benzer echo "$foo".

İfadeyi kullanırken, testsonuç kullanılan operatörlere bağlıdır.

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
                         # evaluates to true/success (returns 0 or null)

Kısacası , sadece geçiş olarak deney şey istiyorsanız / (aka / "doğru" "yanlış") başarısız, sonra bir komut geçmesi ifveya &&parantez olmadan, vb açıklamada. Karmaşık karşılaştırmalar için uygun operatörlerle parantez kullanın.

Ve evet, orada Bash yerli boolean tipi diye bir şey var, o da farkındayım ifve [ve trueteknik olarak "komutları" değil "ifadeleri" dir; bu sadece çok temel ve işlevsel bir açıklamadır.


1
FYI, kodunuzda 1/0 doğru / yanlış olarak kullanmak istiyorsanız, veya için (undefined) if (( $x )); then echo "Hello"; fimesajını gösterir x=1ancak göstermez . x=0x=
Jonathan H

3

Ben gibi bir şey çalıştırarak bazı temel mantık yapabileceğini bulundu:

A=true
B=true
if ($A && $B); then
    C=true
else
    C=false
fi
echo $C

6
Biri olabilir , ama bu gerçekten kötü bir fikir. ( $A && $B )şaşırtıcı bir şekilde verimsiz bir işlemdir - bir alt süreci çağırmak suretiyle ortaya çıkarırsınız fork(), daha sonra $Aöğelerin bir listesini (bu boyutta bir örnek) oluşturmak için içeriğini dize böler ve her öğeyi bir glob olarak değerlendirirsiniz (bu durumda bir ve sonuç olarak bir komut olarak çalıştırılır (bu durumda yerleşik bir komut).
Charles Duffy

3
Ayrıca, dizeleriniz trueve falsedizeleriniz başka bir yerden geliyorsa, gerçekte trueveya dışındaki içerikleri içerme riski vardır falseve rasgele komut yürütmesine kadar ve beklenmedik davranışlar elde edebilirsiniz.
Charles Duffy

6
Boş bir dizeyi false ve boş olmayan bir dizeyi true olarak kabul eden yazmak ve - sayısal olarak muamele etmek - çok, çok daha güvenlidir . A=1; B=1if (( A && B ))[[ $A && $B ]]
Charles Duffy

3
(yalnızca yanıt tarafından oluşturulan kuralları izlemek için yukarıdaki tümüyle büyük harf değişkeni adlarını kullandığımı unutmayın - POSIX aslında ortam değişkenleri ve kabuk yerleşikleri için kullanılacak tüm büyük harf adlarını açıkça belirtir ve küçük harf adlarını uygulama kullanımı için ayırır; gelecekteki işletim sistemi ortamlarıyla çatışmaları önlemek için, özellikle kabuk değişkeni ayarlamanın benzer herhangi bir ortam değişkeninin üzerine yazması düşünüldüğünde, bu kuralı kendi komut dosyalarında kullanmak her zaman idealdir).
Charles Duffy

Anlayışlarınız için teşekkürler!
Rodrigo

2

True / false kullanılması bazı parantez karmaşasını kaldırır ...

#! /bin/bash    
#  true_or_false.bash

[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false

$sourced && echo "SOURCED"
$sourced || echo "CALLED"

# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"

$sourced && return || exit

Bunu yararlı buldum ama ubuntu 18.04 $ 0 "-bash" ve basename komutu bir hata attı. [[ "$0" =~ "bash" ]] Komut dosyasının benim için çalışmasını sağlamak için bu testi değiştirmek .
WiringHarness
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.