क्या अन्य कथन तार्किक और && या के बराबर हैं || और मुझे एक को दूसरे पर कहां प्राथमिकता देना चाहिए?


27

मैं निर्णय लेने की संरचनाओं के बारे में सीख रहा हूं और मैं इन कोडों में आया हूं:

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


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

दोनों एक जैसा व्यवहार करते हैं। क्या एक तरह से दूसरे का उपयोग करने के कोई फायदे हैं?



3
वे समकक्ष नहीं हैं । इकारस द्वारा उत्कृष्ट उत्तर देखें। उदाहरण के लिए, उस मामले पर विचार करें जो ./ffile मौजूद है लेकिन पठनीय नहीं है।
21


जवाबों:


26

नहीं, निर्माण if A; then B; else C; fiऔर समतुल्य नहींA && B || C हैं ।

if A; then B; else C; fiकमांड के साथ , Aहमेशा मूल्यांकन और निष्पादित किया जाता है (कम से कम इसे निष्पादित करने का प्रयास किया जाता है) और फिर कमांड Bया कमांड Cका मूल्यांकन और निष्पादन किया जाता है।

साथ A && B || Cमें, यह आदेश के लिए ही है Aऔर Bलेकिन के लिए अलग C: आदेश Cका मूल्यांकन किया और मार डाला जाता है, तो या तो A विफल रहता है या B विफल रहता है।

अपने उदाहरण में, आपको लगता है chmod u-r ./myfile, फिर, [ -f ./myfile ]सफल होने के बावजूद , आप करेंगेcat /home/user/myfile

मेरी सलाह: उपयोग A && Bया A || Bआप सभी चाहते हैं, यह पढ़ने और समझने में आसान है और कोई जाल नहीं है। लेकिन अगर आपका मतलब है कि ... फिर ... और ... तो उपयोग करें if A; then B; else C; fi


29

अधिकांश लोगों को if... then... else... fiफ़ॉर्म को समझना आसान लगता है ।

आपके लिए a && b || c, आपको यह सुनिश्चित करना होगा कि यह bसही है। यह सूक्ष्म कीड़े का एक कारण है और इस शैली से बचने का एक अच्छा कारण है। यदि b सही नहीं है तो ये समान नहीं हैं।

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

बहुत कम परीक्षणों और कार्यों के लिए जो एक और खंड नहीं है, छोटा लंबाई आकर्षक है, जैसे

 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

&&और ||कर रहे हैं short circuiting operators, जैसे ही परिणाम में जाना जाता है आगे अनावश्यक परीक्षण को छोड़ दिया है। a && b || cके रूप में समूहीकृत है (a && b) || c। पहले aचलाया जाता है। यदि इसे fails0 के निकास स्थिति को वापस नहीं करने के रूप में परिभाषित किया गया है, तो समूह (a && b)को जाना जाता है failऔर bउसे चलाने की आवश्यकता नहीं है। ||पता नहीं है अभिव्यक्ति का परिणाम तो अमल करने की जरूरत है c। यदि aसफल होता है (शून्य लौटता है) तो &&ऑपरेटर को अभी तक पता नहीं है कि इसका परिणाम पता लगाने के a && bलिए दौड़ना bहोगा। यदि bसफल होता है तो a && bसफल होता है और ||जानता है कि समग्र परिणाम सफलता है, इसलिए इसे चलाने की आवश्यकता नहीं है c। अगर bअसफल हो गया तो||अभी भी अभिव्यक्ति का मूल्य नहीं जानता है, इसलिए इसे चलाने की आवश्यकता है c


7

ऑपरेटर और& अगली कमांड को निष्पादित करता है यदि पिछली कमांड में एक सफल निष्पादन था, (एक्जिट कोड ($?) 0 = तार्किक सत्य लौटा दिया गया)।

प्रपत्र में A && B || C, आदेश (या हालत) एक मूल्यांकन किया जाता है और अगर एक रिटर्न सच (सफलता, बाहर निकलें कोड 0) तो आदेश बी निष्पादित किया जाता है। यदि A विफल हो जाता है (इस प्रकार गलत - 0 के अलावा बाहर निकलने का कोड) और / या B विफल हो जाता है ( गलत वापस लौटता है ) तो कमांड C निष्पादित हो जाएगी।

इसके अलावा &&ऑपरेटर एक के रूप में प्रयोग किया जाता है और हालत की जांच और ऑपरेटर में ||की तरह काम करता है या हालत की जाँच में।

आप अपनी स्क्रिप्ट के साथ क्या करना चाहते हैं, इस पर निर्भर करते हुए, फॉर्म A && B || Cका उपयोग आपके उदाहरण की तरह स्थिति जांच के लिए किया जा सकता है या चेन कमांड्स के लिए उपयोग किया जा सकता है और कमांड की एक श्रृंखला सुनिश्चित करने के लिए निष्पादित किया जा सकता है यदि पिछले कमांड में एक सफल निकास कोड 0 था
यही कारण है कि ऐसा लगता है कि आदेश देखने के लिए आम बात है यह है:
do_something && do_something_else_that_depended_on_something

उदाहरण:
apt-get update && apt-get upgrade यदि अद्यतन विफल रहता है, तो अपग्रेड निष्पादित नहीं किया जाता है, (वास्तविक दुनिया में समझ में आता है ...)।

mkdir test && echo "Something" > test/file
भाग echo "Something"तभी निष्पादित किया जाएगा जब mkdir testसफल रहा और ऑपरेशन से बाहर निकलें कोड 0

./configure --prefix=/usr && make && sudo make install
आमतौर पर जॉब को कंपाइल करने के लिए जरूरी डिपेंडेंट कमांड्स को एक साथ मिलाने पर।

यदि आप "चेन" से ऊपर को लागू करने का प्रयास करते हैं, तो - तब - अन्यथा आपको एक सरल कार्य के लिए बहुत अधिक कमांड और चेक (और इस प्रकार लिखने के लिए अधिक कोड - गलत होने के लिए अधिक चीजें) की आवश्यकता होगी।

इसके अलावा, ध्यान रखें कि && के साथ जंजीर कमांड और || बाईं ओर दाईं ओर शेल द्वारा पढ़ा जाता है। आपको कुछ पिछले आदेशों के सफल आउटपुट पर अगले चरण पर निर्भर करने के लिए कोष्ठक के साथ समूह कमांड और कंडीशन चेक की आवश्यकता हो सकती है। उदाहरण के लिए इसे देखें:

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

या एक वास्तविक जीवन उदाहरण:

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

ध्यान रखें कि कुछ कमांड निष्पादित की गई प्रक्रिया के आधार पर अलग-अलग निकास कोड लौटाते हैं, या उनके कार्यों के आधार पर अलग-अलग कोड लौटाते हैं, (उदाहरण के लिए GNU कमांड diff, 1 अगर दो फाइलें अलग-अलग होती हैं, और 0 यदि वे नहीं करते हैं)। इस तरह के आदेशों की देखभाल के लिए && और ||

इसके अलावा बस सभी पहेली को एक साथ करने के लिए, ;ऑपरेटर का उपयोग करने वाले आदेशों को ध्यान में रखें । एक प्रारूप के साथ A;B;Cसभी आदेशों को श्रृंखला में निष्पादित किया जाएगा, चाहे कोई भी कमांड का निकास कोड हो Aऔर B


1

इसके बारे में बहुत सी उलझनें इन और OR सूचियों को कॉल करने वाले बैश प्रलेखन के कारण हो सकती हैं । जबकि तार्किक रूप से वर्ग कोष्ठक के अंदर &&और समान ||पाए जाते हैं, वे अलग-अलग कार्य करते हैं।

कुछ उदाहरणों में यह सबसे अच्छा हो सकता है ...

नोट: सिंगल और डबल स्क्वायर ब्रैकेट ( [ ... ]और [[ ... ]]) अपने आप में कमांड हैं जो एक तुलना करते हैं और एक निकास कोड लौटाते हैं। उन्हें वास्तव में जरूरत नहीं है if

cmda  && cmdb  || cmdc

यदि cmdaसच बाहर निकलता है, cmdbतो निष्पादित किया जाता है।
यदि cmdaगलत निकलता है, cmdbतो निष्पादित नहीं किया जाता है, लेकिन cmdcहै।

cmda; cmdb  && cmdc  || cmdd

cmdaनिकास को कैसे अनदेखा किया जाता है।
यदि cmdbसच बाहर निकलता है, cmdcतो निष्पादित किया जाता है।
यदि cmdbगलत निकलता है, cmdcतो निष्पादित नहीं किया जाता है और cmddहै।

cmda  && cmdb; cmdc

यदि cmdaसच बाहर निकलता है, cmdbनिष्पादित किया जाता है, उसके बाद cmdc
यदि cmdaगलत निकलता है, cmdbतो निष्पादित नहीं किया जाता है लेकिन cmdcहै।

है ना? क्यों cmdcअंजाम दिया जाता है?
क्योंकि व्याख्याकार के लिए, एक अर्धविराम ( ;) और एक नई पंक्ति का अर्थ बिल्कुल एक ही बात है। बैश कोड की उस लाइन को इस रूप में देखता है ...

cmda  && cmdb
cmdc  

जो अपेक्षित है, उसे प्राप्त करने के लिए, हमें cmdb; cmdcउन्हें कंपाउंड कमांड (समूह कमांड) बनाने के लिए घुंघराले ब्रेसिज़ के अंदर संलग्न करना होगा । अतिरिक्त समाप्ति अर्धविराम { ...; }सिंटैक्स की केवल एक आवश्यकता है । तो हम प्राप्त करते हैं ...

cmda && { cmdb; cmdc; }
यदि cmdaसच बाहर निकलता है, cmdbनिष्पादित किया जाता है, उसके बाद cmdc
यदि cmdaबाहर निकलता है झूठा, न तो cmdbया cmdcमार डाला जाता है।
अगली पंक्ति के साथ निष्पादन जारी है।

प्रयोग

सशर्त कमांड सूचियां फ़ंक्शन से जितनी जल्दी हो सके लौटने के लिए सबसे अधिक उपयोगी होती हैं और इस प्रकार बहुत सारे अनावश्यक कोड की व्याख्या करने और निष्पादित करने से बचती हैं। हालांकि, कई फ़ंक्शन रिटर्न का मतलब यह है कि कार्यों को छोटा रखने के बारे में जुनूनी होना चाहिए ताकि यह सुनिश्चित करना आसान हो कि सभी संभावित शर्तों को कवर किया गया है।

यहाँ कुछ चल रहे कोड से एक उदाहरण है ...

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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.