Başka bir deyim mantıksal ve && veya || ve birini diğerine göre nerede tercih etmeliyim?


27

Karar verme yapılarını öğreniyorum ve şu kodlara rastladım:

if [ -f ./myfile ]
then
     cat ./myfile
else
     cat /home/user/myfile
fi


[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile

İkisi de aynı şekilde davranır. Birini diğerinden kullanmanın herhangi bir avantajı var mı?



3
Onlar değil eşdeğeri. Icarus'un mükemmel cevabını görün. Örneğin, ./myfile dosyasının var olduğunu ancak okunamadığını düşünün.
AlexP


Yanıtlar:


26

Hayır, yapılar if A; then B; else C; five A && B || Cvardır eşdeğer değildir .

İle if A; then B; else C; fikomut Aher zaman değerlendirilir ve yürütülür (en azından çalıştırma denemesi yapılır) ve sonra komut Bveya komut Cdeğerlendirilir ve yürütülür.

İle A && B || C, bu komutlar için aynıdır Ave Bancak farklı C: komuta Ceğer değerlendirilir ve yürütülür ya A başarısız ya da B başarısız olur.

Örnekte, farz edelim ki chmod u-r ./myfile, o zaman, [ -f ./myfile ]başarılı olmanıza rağmen ,cat /home/user/myfile

Tavsiyem: İstediğiniz A && Bveya A || Bistediğiniz tüm bu, okumak ve anlamak kolay kalır ve tuzak yoktur. Ama eğer demek istiyorsan ... öyleyse ... başka ... o zaman kullan if A; then B; else C; fi.


29

Çoğu insan if... then... else... fiformunu kavramayı daha kolay bulur .

Bunun a && b || cdoğru olduğuna emin olmalısın b. Bu, ince hataların bir nedenidir ve bu tarzdan kaçınmak için iyi bir nedendir. B doğru dönmezse, bunlar aynı değildir.

 $ if true; then false ; else echo boom ; fi
 $ true && false || echo boom
 boom

Başka bir maddeye sahip olmayan çok kısa testler ve eylemler için, kısaltılmış uzunluk çekicidir, örn.

 die(){ printf "%s: %s\n" "$0" "$*" >&2 ; exit 1; }

 [ "$#" -eq 2] || die "Needs 2 arguments, input and output"

 if [ "$#" -ne 2 ] ; then
     die "Needs 2 arguments, input and output"
 fi

&&ve ||olduğu short circuiting operatorskısa sürede sonuç bilindiği gibi daha ileri gereksiz testler atlanır. a && b || colarak gruplandırılmıştır (a && b) || c. İlk açalıştırıldı. O takdirde failshangi ardından grup 0 çıkış durumu, dönen değil olarak tanımlanır (a && b)bilinmektedir failve bçalıştırılması gerekmez. ||İfadenin sonucu öylesine yürütmek gerekiyor bilmiyor c. aBaşarılı olursa (sıfır döndürürse), &&operatör henüz ifadenin değerini bilmiyorsa, henüz sonucunu bilmiyordur, bu nedenle çalışması gerekir .a && b için koşmak bzorunda değildir. Eğer bbaşarılı olursa, başarılı a && bolur ve ||genel sonucun başarı olduğunu bilir, bu yüzden kaçması gerekmez c. Eğer bo zaman başarısız||c


7

Operator && bir sonraki komutu yürütürse, eğer önceki komut başarılı bir şekilde yürütülürse, (return kodunu döndürdü ($?) 0 = mantıksal doğru).

Formunda A && B || C, komutu (veya durum) bir değerlendirilir ve eğer bir döner doğru (başarı, çıkış kodu 0) komut B yürütülür. Eğer A başarısız olursa (bu nedenle false döndürür - 0 dışında çıkış kodu) ve / veya B başarısız olursa ( false döndürür ) C çalıştırılır.

Ayrıca &&operatör bir AND olarak kontrollerde kullanılır ve operatör VEYA|| gibi çalışır durum kontrollerinde .

Komut dosyanızla ne yapmak istediğinize bağlı olarak, form A && B || Cörneğin örneğiniz gibi durum kontrolleri için kullanılabilir veya komutları zincirlemek için kullanılabilir ve önceki komutların başarılı bir çıkış kodu 0 olması durumunda yürütülecek bir dizi komutun olmasını sağlamak için kullanılabilir .
Bu nedenle, aşağıdaki gibi komutları görmek yaygındır:
do_something && do_something_else_that_depended_on_something .

Örnekler:
apt-get update && apt-get upgrade Güncelleme başarısız olursa, yükseltme gerçekleştirilmez, (gerçek dünyada mantıklı ...).

mkdir test && echo "Something" > test/file
Parça echo "Something"sadece mkdir testbaşarılı olursa çalıştırılır ve işlem 0 çıkış kodunu döndürür .

./configure --prefix=/usr && make && sudo make install
Genellikle gerekli bağımlı komutları bir araya getirmek için işleri derlerken bulunur.

Eğer yukarıdaki "zincirleri" uygularsanız if - then - else ile basit bir görev için çok daha fazla komuta ve kontrol (ve böylece daha fazla kod yazmak için - daha fazla yanlış iş) gerekir.

Ayrıca, && ve || soldan sağa doğru kabuk tarafından okunur. Önceki komutların başarılı çıktısına bir sonraki basamağa bağlı olarak komutları ve koşul kontrollerini gruplandırmanız gerekebilir. Örneğin şuna bakın:

root@debian:$ true || true && false;echo $?
1 
#read from left to right
#true OR true=true AND false = false = exit code 1=not success

root@debian:$ true || (true && false);echo $?
0 
# true OR (true AND false)=true OR false = true = exit code 0 = success

Veya gerçek hayattan bir örnek:

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 ]] && [[ $c -eq 2 ]];echo $?
1 
#condition $a = true OR condition b = true AND condition $c = false
#=> yields false as read from left to right, thus exit code=1 = not ok

root@debian:$ a=1;b=1;c=1;[[ $a -eq 1 ]] || [[ $b -eq 1 && $c -eq 2 ]];echo $?
0 
#vars b and c are checked in a group which returns false, 
#condition check of var a returns true, thus true OR false yields true = exit code 0

(Örnek komut GNU için bazı komutlar infaz sürecine bağlı olarak farklı çıkış kodları unutmayın, ya iade farklı kodları eylemlerinin bağlı diff, döner 1 iki eğer dosyalar farklıdır ve 0 gelmezlerse). Bu tür komutların && ve ||.

Ayrıca tüm bulmacayı bir araya getirmek için, ;operatörü kullanarak komutların birleştirilmesine dikkat edin . Bir biçim sayesinde A;B;Ctüm komutlar olursa olsun komutun çıkış kodu ne seride yürütülecektir Ave B.


1

Bununla ilgili karışıklığın çoğu, bu VE ve VEYA listelerini çağıran bash belgelerine bağlı olabilir . Mantıksal olarak &&ve ||köşeli parantezlerin içinde bulunsalar da, farklı şekilde çalışırlar.

Bazı örnekler bunu en iyi şekilde açıklayabilir ...

NOT: Tek ve çift köşeli parantezler ( [ ... ]ve [[ ... ]]) kendi başlarına bir karşılaştırma yapan ve bir çıkış kodu döndüren komutlardır. Aslında buna ihtiyaçları yok if.

cmda  && cmdb  || cmdc

Eğer cmdaçıkışlar gerçek, cmdbyürütülür.
Yanlış cmdaçıkarsa, cmdbyürütülmez, ama cmdcyapılır.

cmda; cmdb  && cmdc  || cmdd

cmdaÇıkışların nasıl görmezden gelindiği.
Eğer cmdbçıkışlar gerçek, cmdcyürütülür.
Eğer cmdbçıkışlar Yanlış, cmdcinfaz ve DEĞİLDİR cmddolduğunu.

cmda  && cmdb; cmdc

Eğer cmdagerçek çıkışlar, cmdbyürütüldüğünde, ardından cmdc.
Yanlış cmdaçıkarsa cmdb, DEĞİL , ama cmdcyapılır.

Ha? Neden cmdcidam edildi?
Çünkü yorumlayıcıya göre, bir noktalı virgül ( ;) ve bir yeni satır aynı anlama gelir. Bash, bu kod satırını ...

cmda  && cmdb
cmdc  

Bekleneni elde etmek cmdb; cmdciçin, onları bir Bileşik Komutu (grup komutu) yapmak için küme parantezlerinin içine almalıyız . Ek sonlandırıcı noktalı virgül yalnızca { ...; }sözdiziminin bir gereğidir . Yani biz ...

cmda && { cmdb; cmdc; }
Eğer cmdagerçek çıkışlar, cmdbyürütüldüğünde, ardından cmdc.
Eğer cmdaçıkışlar yalancı, ne cmdbya cmdcyürütülür.
Yürütme bir sonraki satırla devam eder.

kullanım

Koşullu komut listeleri, işlevlerden mümkün olan en kısa sürede geri dönmek ve bu nedenle çok fazla gereksiz kodun yorumlanmasından ve yürütülmesinden kaçınmak için kullanışlıdır. Çoklu işlev dönüşleri, işlevlerin kısa tutulması konusunda takıntılı olması gerektiği anlamına gelir, bu nedenle tüm olası koşulların kapsandığından emin olmak daha kolaydır.

İşte bazı çalışan kodlardan bir örnek ...

fnInit () {
  :
  _fn="$1"
  ### fnInit "${FUNCNAME}" ...
  ### first argument MUST be name of the calling function
  #
  [[ "$2" == "--help-all" ]]  && { helpAll                      ; return 0; }
  ### pick from list of functions
  #
  [[ "$2" == "--note-all" ]]  && { noteAll                      ; return 0; }
  ### pick from notes in METAFILE
  #
  [[ "$2" == "--version"  ]]  && { versionShow "${_fn}" "${@:3}"; return 0; }
  #
  [[ "$2" == "--function" ]]  && {
    isFnLoaded "$3"           && { "${@:3}"                     ; return 0; }
    #
    errorShow functionnotfound "Unknown function:  $3"
    return 0
  }
  ### call any loaded function
  #
  [[ "$2" == "--help" || "$2" == "-h" ]]  && { noteShow "$_fn" "${@:3}"; return 0; }
  ### fnInit "${FUNCNAME}" --help or -h
  #
  return 1
}
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.