Bash işlevinden bir boole döndürme


211

Bir dosyanın belirli özelliklere sahip olup olmadığını ve true veya false döndürüp döndürmediğini kontrol eden bir bash işlevi yazmak istiyorum. Sonra "if" komut dosyalarında kullanabilirsiniz. Ama ne dönmeliyim?

function myfun(){ ... return 0; else return 1; fi;}

o zaman böyle kullanın:

if myfun filename.txt; then ...

Tabii ki bu işe yaramıyor. Bu nasıl yapılabilir?


3
functionanahtar kelimeyi bırak , myfun() {...}yeterlidir
glenn jackman

2
Ne için önemli ifsıfır çıkış durumudur myfun: eğer myfunçıkılıyor 0, then ...yürütülür; başka bir şey varsa else ...yürütülür.
Eelvex

7
@nhed: functionanahtar kelime bir bashizmdir ve diğer bazı kabuklarda sözdizimi hatalarına neden olur. Temel olarak, ya gereksiz ya da yasak, neden kullanıyorsunuz? Bir grep hedefi olarak bile kullanışlı değildir, çünkü orada olmayabilir ( ()bunun yerine grep ).
Gordon Davisson

3
@GordonDavisson: ne? başka mermiler var mı? ;-)
nhed

Lütfen 0 ve 1 kullanmayın. Bkz. Stackoverflow.com/a/43840545/117471
Bruno Bronosky

Yanıtlar:


333

True için 0 ve false için 1 kullanın.

Örneklem:

#!/bin/bash

isdirectory() {
  if [ -d "$1" ]
  then
    # 0 = true
    return 0 
  else
    # 1 = false
    return 1
  fi
}


if isdirectory $1; then echo "is directory"; else echo "nopes"; fi

Düzenle

@ Amichair'in yorumundan, bunlar da mümkündür

isdirectory() {
  if [ -d "$1" ]
  then
    true
  else
    false
  fi
}


isdirectory() {
  [ -d "$1" ]
}

4
Hayır, bunu yapmanız gerekmez - örneğe bakın.
Erik

46
Daha iyi okunabilirlik için 'true' komutunu (hiçbir şey yapmaz ve başarıyla tamamlar, yani 0 döndürür) ve 'false' komutunu (hiçbir şey yapmaz ve başarısız bir şekilde tamamlar, yani sıfır olmayan bir değer döndürür) kullanabilirsiniz. Ayrıca, açık bir return ifadesi olmadan biten bir işlev, son yürütülen komutun çıkış kodunu döndürür, bu nedenle yukarıdaki örnekte, işlev gövdesi yalnızca azaltılabilir [ -d "$1" ].
amichair

24
Bengt: "hata kodu" olarak düşündüğünüzde mantıklı: hata kodu 0 = her şey yolunda gitti = 0 hata; hata kodu 1 = bu çağrının yapması gereken ana şey başarısız oldu; başka: başarısız! manpage'e bak.
uçan koyun

7
Programlamada bir şeyin genellikle sadece bir şekilde başarılı olabileceğini, ancak sonsuz yollarla başarısız olabileceğini düşündüğünüzde mantıklıdır . Belki sonsuz değil, ama çok, ihtimaller bize karşı yığılmış. Başarı / Hata (lar) boolean değil. Bence bu "true için 0, false için 1 kullanın." "Başarı için 0, başarısızlık için sıfır değil" yazmalıdır.
Davos

6
Lütfen 0 ve 1 kullanmayın. Bkz. Stackoverflow.com/a/43840545/117471
Bruno Bronosky

167

250'den fazla oylama cevabı olmasına rağmen neden söylediğime önem vermelisin?

Bu 0 = trueve değil 1 = false. Sıfır : hata olmaması (başarı) ve sıfır olmayan arıza (N tipi) anlamına gelir .

İken seçilen cevap teknik olarak "doğru" olduğunu lütfen koymayın return 1için kodunuzda ** YANLıŞ . Birkaç talihsiz yan etkisi olacaktır.

  1. Deneyimli geliştiriciler sizi amatör olarak görecektir (aşağıdaki nedenden dolayı).
  2. Deneyimli geliştiriciler bunu yapmaz (aşağıdaki tüm nedenlerden dolayı).
  3. Hata eğilimli.
    • Deneyimli geliştiriciler bile 0 ve 1'i sırasıyla yanlış ve doğru olarak karıştırırlar (yukarıdaki nedenden dolayı).
  4. Aşırı ve saçma yorumlar gerektirir (veya teşvik edecektir).
  5. Aslında örtük dönüş durumlarından daha az yardımcı olur.

Biraz bash öğrenin

Bash manuel diyor (vurgu benim)

dönüş [n]

Çalıştırmayı durdurmak ve n değerini arayana döndürmek için bir kabuk işlevine neden olun. N sağlanmazsa , dönüş değeri işlevde yürütülen son komutun çıkış durumudur .

Bu nedenle, DOĞRU ve Yanlış belirtmek için HİÇ 0 ve 1 kullanmamız gerekmez. Bunu yapmaları, aslında sadece kodun hatalarını ayıklamak, röportaj soruları ve yeni başlayanların zihinlerini uçurmak için yararlı olan önemsiz bir bilgidir.

Bash el kitabı ayrıca

aksi takdirde işlevin dönüş durumu, yürütülen son komutun çıkış durumudur

Bash el kitabı ayrıca

( $? ) En son yürütülen ön plan boru hattının çıkış durumuna genişler .

Vay, bekle. Boru hattı? Diyelim bash manuel için dönüş bir kez daha.

Bir boru hattı, kontrol operatörlerinden biriyle ayrılmış bir veya daha fazla komutun bir dizisidir '|' veya '| &'.

Evet. 1 komutun bir boru hattı olduğunu söylediler. Bu nedenle, bu alıntıların 3'ü de aynı şeyi söylüyor.

  • $? en son ne olduğunu anlatır.
  • Kabarcıkları.

Cevabım

Yani, @Kambus böyle basit bir işlevle, hiç returngerek olmadığını gösterdi. Bunu okuyacak çoğu insanın ihtiyaçlarına kıyasla gerçekçi olmayan bir şekilde basit olduğunu düşünüyorum.

Neden return?

Bir işlev son komutunun çıkış durumunu döndürecekse, neden returnhiç kullanıyorsunuz ? Çünkü bir işlev yürütmeyi durdurur.

Birden çok koşulda yürütmeyi durdurma

01  function i_should(){
02      uname="$(uname -a)"
03
04      [[ "$uname" =~ Darwin ]] && return
05
06      if [[ "$uname" =~ Ubuntu ]]; then
07          release="$(lsb_release -a)"
08          [[ "$release" =~ LTS ]]
09          return
10      fi
11
12      false
13  }
14
15  function do_it(){
16      echo "Hello, old friend."
17  }
18
19  if i_should; then
20    do_it
21  fi

Burada ne var ...

Satır 04açık bir [-ish] dönüşüdür çünkü RHS değeri &&yalnızca LHS doğruysa yürütülür

Satır 09, satır durumuyla eşleşen doğru veya yanlış döndürür08

Satır 13, satır nedeniyle yanlış döndürür12

(Evet, bu golf edilebilir, ancak tüm örnek kabul edilir.)

Başka bir ortak desen

# Instead of doing this...
some_command
if [[ $? -eq 1 ]]; then
    echo "some_command failed"
fi

# Do this...
some_command
status=$?
if ! $(exit $status); then
    echo "some_command failed"
fi

Bir statusdeğişken belirlemenin anlamını nasıl belirlediğine dikkat edin $?. (Elbette bunun ne $?anlama geldiğini biliyorsunuz , ancak bir gün Google'dan daha az bilgili biri var. Kodunuz yüksek frekanslı ticaret yapmıyorsa, biraz sevgi gösterin , değişkeni ayarlayın.) Ama asıl paket şu ki " durum yok "veya tersine" çıkış durumu varsa "yüksek sesle okunabilir ve anlamlarını açıklayabilir. Ancak, sonuncusu biraz iddialı exitolabilir , çünkü kelimeyi görmek size senaryodan çıktığını düşündürür, gerçekte $(...)alt kabuktan çıkarken .


** Kesinlikle return 1yanlış için kullanmakta ısrar ederseniz, return 255bunun yerine en azından kullanmanızı öneririm . Bu, gelecekteki benliğinizin veya kodunuzu koruması gereken herhangi bir geliştiricinin "neden bu 255?" O zaman en azından dikkat edecekler ve bir hatadan kaçınma şansları daha yüksek olacaktır.


1
@ZeroPhase 1 & 0 yanlış ve doğru için saçma olurdu. İkili bir veri tipiniz varsa, bunun için bir neden yoktur. Bash ile uğraştığınız şey, başarıyı (tekil) ve başarısızlıkları (çoğul) yansıtan bir durum kodudur . " ifBaşarı bunu yap, elsebunu yap." Ne başarısı var? Doğru / yanlış olup olmadığını kontrol ediyor olabilir, bir dize, tamsayı, dosya, dizin, yazma izinleri, glob, regex, grep veya hataya maruz kalan herhangi bir komutu kontrol ediyor olabilir .
Bruno Bronosky

3
0 / 1'in standart kullanımından kaçınmak, sadece geniş ve karışıklığa eğilimli olduğu için bir dönüş değeri olarak saçmadır. Kabuk dilinin tamamı geniş ve karışıklığa eğilimlidir. Bash kendisi kendi içinde 0/1 = doğru / yanlış kuralını kullanır trueve falsekomutları. Yani, anahtar kelime truetam anlamıyla 0 durum kodu olarak değerlendirilir. Ayrıca, eğer doğası gereği if-then ifadeleri başarı kodları yerine booleanlar üzerinde çalışır. Boole işlemi sırasında bir hata oluşursa, doğru veya yanlış döndürmemeli, yalnızca yürütmeyi kesmelidir. Aksi takdirde yanlış pozitifler (pun) alırsınız.
Beejor

1
"if! $ (çıkış $ status); o zaman" - Bu daha iyi bir açıklamayı hak ediyor. Sezgisel değil. İletiyi yazdırmadan önce programın çıkıp çıkmayacağını düşünmem gerekiyor. Cevabınızın geri kalanı iyiydi, ama bu onu bozdu.
Craig Hicks

1
@BrunoBronosky Cevabınızı okudum ve içerik boru hattı (stdin-> stdout) ile dönüş değerlerindeki hata kodları arasındaki farkı anladığımı düşünüyorum. Ancak, neden kullanmaktan return 1kaçınılması gerektiğini anlamıyorum . Bir validatefonksiyonum olduğunu varsayarsak return 1, doğrulama başarısız olursa makul buluyorum . Sonuçta, bir komut dosyasının düzgün işlenmediği durumlarda (örneğin, kullanırken set -e) yürütülmesini durdurmak için bir nedendir .
JepZ

1
@Jepz bu harika bir soru. Bunun return 1geçerli olduğunu doğru söylüyorsunuz . Benim endişem burada "0 = true 1 = false [negatif sözcük ekleyin]" diyen tüm yorumlar. Bu insanlar muhtemelen bir gün kodunuzu okuyacak. Bu yüzden onlar için return 255(ya da 42 ya da hatta 2) görmek daha fazla düşünmelerine ve “gerçek” olarak hata yapmamalarına yardımcı olmalıdır. set -ehala yakalayacak.
Bruno Bronosky

31
myfun(){
    [ -d "$1" ]
}
if myfun "path"; then
    echo yes
fi
# or
myfun "path" && echo yes

1
Olumsuzluk ne olacak?
einpoklum

Buna ne dersin, @einpoklum?
Mark Reed

@MarkReed: Yani "else" örneğini örneğinize eklemek istedim.
einpoklum

myfun "yol" || yankı yok
Hrobky

13

Sadece -d seçeneği ile dizini kontrol ederken dikkatli olun!
$ 1 değişkeni boşsa, kontrol yine de başarılı olacaktır. Emin olmak için değişkenin boş olmadığını da kontrol edin.

#! /bin/bash

is_directory(){

    if [[ -d $1 ]] && [[ -n $1 ]] ; then
        return 0
    else
        return 1
    fi

}


#Test
if is_directory $1 ; then
    echo "Directory exist"
else
    echo "Directory does not exist!" 
fi

1
Sorunun bu soruyu nasıl yanıtladığı konusunda emin değilim. Boş bir $ 1'in boş olduğunda true değerini döndürebileceğini bilmek güzel olsa da, bash işlevinden true veya false döndürme konusunda herhangi bir fikir vermez. Yeni bir soru oluşturmayı öneririm "Boş kabuk değişkeninde bir test yaptığınızda ne olur?" Ve sonra bunu cevap olarak gönderiyoruz.
DRaehal

3
$1( "$1") Öğesine doğru tırnak işareti eklerseniz boş bir değişken olup olmadığını kontrol etmeniz gerekmediğini unutmayın. Bu bir dizin olmadığından [[ -d "$1" ]]başarısız olur "".
morgents

3

Üzerinde tökezlediğim bir noktaya (açıkça belirtilmemiş mi?) Rastladım. Yani, booleanın nasıl döndürüleceği değil, nasıl doğru bir şekilde değerlendirileceği!

Söylemeye çalışıyordum if [ myfunc ]; then ..., ama bu sadece yanlış. Parantezleri kullanmamalısınız! if myfunc; then ...bunu yapmanın yolu.

İtibariyle @Bruno ve diğerleri yineledi, trueve falseolan komutlar değil değerleri,! Kabuk komut dosyalarındaki boolean'ları anlamak çok önemlidir.

Bu yazıda, boolean değişkenlerini kullanarak açıkladım ve gösterdim : https://stackoverflow.com/a/55174008/3220983 . Bunu kontrol etmenizi şiddetle tavsiye ediyorum, çünkü çok yakından ilgili.

Burada, işlevlerden booleanları döndürmek ve değerlendirmek için bazı örnekler vereceğim :

Bu:

test(){ false; }                                               
if test; then echo "it is"; fi                                 

Eko çıktı üretmez. (yani yanlış false döndürür )

test(){ true; }                                                
if test; then echo "it is"; fi                                 

üretir:

it is                                                        

(örn. doğru true döndürür )

Ve

test(){ x=1; }                                                
if test; then echo "it is"; fi                                 

üretir:

it is                                                                           

Çünkü 0 (yani true) dolaylı olarak döndürüldü .

Şimdi, bu beni mahvediyordu ...

test(){ true; }                                                
if [ test ]; then echo "it is"; fi                             

üretir:

it is                                                                           

VE

test(){ false; }                                                
if [ test ]; then echo "it is"; fi                             

AYRICA üretir:

it is                                                                           

Buradaki parantezleri kullanmak yanlış bir pozitif üretti ! ("Dış" komut sonucunu 0 çıkarıyorum.)

Gönderimdeki en önemli şey: tipik bir eşitlik kontrolü için yaptığınız gibi bir boole işlevini (veya değişkeni) değerlendirmek için parantez kullanmayın if [ x -eq 1 ]; then...!


2

Kullanın trueveya falsehemen öncesinde komutları returnsonra, returnhiçbir parametrelerle. returnOtomatik son komutun değerini kullanır.

return1 veya 0 kullanmıyorsanız argüman sağlama tutarsız, spesifik yazın ve hataya yatkın.

#!/bin/bash

function test_for_cat {
    if [ $1 = "cat" ];
    then
        true
        return
    else
        false
        return
    fi
}

for i in cat hat;
do
    echo "${i}:"
    if test_for_cat "${i}";
    then
        echo "- True"
    else
        echo "- False"
    fi
done

Çıktı:

$ bash bash_return.sh

cat:
- True
hat:
- False

1

Bunu bu function myfun(){ ... return 0; else return 1; fi;}şekilde yeniden yazarsanız işe yarayabilir function myfun(){ ... return; else false; fi;}. Yani, falsefonksiyondaki son talimat, tüm fonksiyon için yanlış sonuç alırsanız, ancak returnfonksiyonu yine de gerçek sonuçla keser. En azından bash tercümanım için doğru olduğuna inanıyorum.


1

Fonksiyon çıktısını test etmek için en kısa formu buldum

do_something() {
    [[ -e $1 ]] # e.g. test file exists
}

do_something "myfile.txt" || { echo "File doesn't exist!"; exit 1; }

1

Kod okunabilirlik nedenlerinden dolayı true / false döndürmenin aşağıdakileri yapması gerektiğine inanıyorum:

  • bir hatta olmak
  • bir komut ol
  • hatırlaması kolay ol
  • anahtar kelimeden ve returnardından başka bir anahtar kelimeden ( trueveya false) bahsedin

Benim çözüm return $(true)veya return $(false)gösterildiği gibi:

is_directory()
{
    if [ -d "${1}" ]; then
        return $(true)
    else
        return $(false)
    fi
}

0

@Bruno Bronosky ve @mrteatime'i takip ederek, boolean dönüşünüzü "geriye" yazmanız önerisini sunuyorum. Demek istediğim bu:

foo()
{
    if [ "$1" == "bar" ]; then
        true; return
    else
        false; return
    fi;
}

Bu, her dönüş ifadesi için çirkin iki satır gereksinimini ortadan kaldırı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.