यदि कथन में शेल में कई स्थितियों का प्रतिनिधित्व कैसे करें?


307

मैं इस तरह कई स्थितियों का प्रतिनिधित्व करना चाहता हूं:

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]   
then  
    echo abc;  
else  
    echo efg;   
fi  

लेकिन जब मैं स्क्रिप्ट पर अमल करता हूं, तो यह पता चलता है

syntax error at line 15: `[' unexpected, 

जहां लाइन 15 एक दिखा रहा है अगर ...

इस हालत में क्या गलत है? मुझे लगता है कि कुछ गड़बड़ है ()


6
आप शेल शर्तों के बारे में नहीं पूछ रहे हैं, लेकिन परीक्षण की स्थिति। आपके उदाहरण में संपूर्ण अभिव्यक्ति का मूल्यांकन test( [) द्वारा किया गया है और शेल द्वारा नहीं। शेल केवल बाहर निकलने की स्थिति का मूल्यांकन करता है [
13

यह भी देखें stackoverflow.com/questions/16203088/...
tripleee

जवाबों:


381

क्लासिक तकनीक (भागने मेटाचैकर्स):

if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi

मैंने $gदोहरे उद्धरणों में संदर्भों को संलग्न किया है ; यह अच्छा अभ्यास है, सामान्य तौर पर। कड़ाई से, कोष्ठक की आवश्यकता नहीं है क्योंकि पूर्ववर्तीता -aऔर -oउनके बिना भी इसे सही बनाती है।

ध्यान दें कि -aऔर -oऑपरेटर मुख्य रूप से बैकवर्ड संगतता के लिए POSIX विनिर्देशन का हिस्सा हैं test, [क्योंकि वे testउदाहरण के लिए (7 वें संस्करण UNIX में एक भाग थे ), लेकिन उन्हें स्पष्ट रूप से POSIX द्वारा 'अश्लील' के रूप में चिह्नित किया गया है। बैश (देखें सशर्त भाव ) के लिए क्लासिक और POSIX अर्थ जगह ले लेना करने लगता है -aऔर -oअपने स्वयं के विकल्प ऑपरेटरों कि तर्क ले के साथ।


कुछ देखभाल के साथ, आप अधिक आधुनिक [[ऑपरेटर का उपयोग कर सकते हैं , लेकिन ध्यान रखें कि बैश और कॉर्न शेल (उदाहरण के लिए) में संस्करण समान नहीं हैं।

for g in 1 2 3
do
    for c in 123 456 789
    do
        if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
        then echo "g = $g; c = $c; true"
        else echo "g = $g; c = $c; false"
        fi
    done
done

उदाहरण रन, मैक ओएस एक्स पर बैश 3.2.57 का उपयोग करके:

g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false

आपको चर के [[रूप में उद्धृत करने की आवश्यकता नहीं है जैसा कि आप करते हैं [क्योंकि यह उसी तरह से एक अलग कमांड नहीं [है।


क्या यह एक क्लासिक सवाल नहीं है?

मैंने ऐसा सोचा होगा। हालांकि, एक और विकल्प है, अर्थात्:

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi

वास्तव में, यदि आप autoconfउपकरण या संबंधित पैकेजों के लिए 'पोर्टेबल शेल' दिशानिर्देश पढ़ते हैं, तो यह नोटेशन - ' ||' और ' &&' का उपयोग करते हुए - यही वह सलाह है। मुझे लगता है कि आप भी इतनी दूर जा सकते हैं:

if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi

जहां क्रियाएं गूंज के रूप में तुच्छ हैं, यह बुरा नहीं है। जब एक्शन ब्लॉक को दोहराया जाना कई लाइनें हैं, तो पुनरावृत्ति बहुत दर्दनाक है और पहले के संस्करणों में से एक बेहतर है - या आपको फ़ंक्शन को विभिन्न thenब्लॉकों में लगाए गए फ़ंक्शन में लपेटने की आवश्यकता है ।


9
यह जानना अच्छा है कि बच गए कोष्ठक काम करते हैं; के रूप में अलग एक: इस विशेष मामले में, कोष्ठक भी जरूरत नहीं होती है, क्योंकि -aवास्तव में की तुलना में अधिक पूर्वता है -o(विपरीत &&और ||खोल में - हालांकि, अंदर bash [[ ... ]] सशर्त , && भी अधिक से अधिक पूर्वता है ||)। आप से बचना चाहते थे, तो -aऔर -oअधिक से अधिक मजबूती और पोर्टेबिलिटी के लिए - जो POSIX आदमी स्वयं पृष्ठ पता चलता है - आप भी इस्तेमाल कर सकते हैं subshells के लिए समूहीकरण:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
mklement0

अच्छा समाधान है, लेकिन मैं रूप की तरह बिना सभी कोष्ठक और कोष्ठक:if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
Mogens TrasherDK

मुझे इसमें थोड़ी देर हो गई है, लेकिन यह अभी भी एक शीर्ष खोज परिणाम है, इसलिए मैं केवल यह ध्यान देना चाहूंगा कि इसका उपयोग करना &&या ||बेहतर होना भी बेहतर है क्योंकि यह अन्य भाषाओं में अधिक सशर्त व्यवहार करता है, और आपको शॉर्ट सर्किट की स्थिति देता है। उदाहरण के लिए if [ -n "${check_inodes}" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]:। इस तरह से करना, यदि check_inodesखाली है, तो आप दो कॉल करने से बचते हैं stat, जबकि एक बड़ी, जटिल परीक्षण स्थिति को निष्पादित करने से पहले सभी तर्कों को संसाधित करना होगा (जो कि उस व्यवहार के बारे में भूल जाने पर बग भी पैदा कर सकता है)।
हरविक्क

182

बैश में:

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]

9
निश्चित रूप से सबसे अच्छा तरीका है bash। एक तरफ एक के रूप में: इस विशेष मामले में कोष्ठकों भी जरूरत नहीं होती है, क्योंकि अंदर [[ ... ]] सशर्त, && वास्तव में की तुलना में अधिक पूर्वता है ||- विपरीत बाहर इस तरह के सशर्त।
mklement0

क्या कोई तरीका है जिससे हम यह पता लगा सकते हैं कि यहाँ किस स्थिति का मिलान हुआ है? क्या यह पहले कोष्ठक में एक था या दूसरा था?
फायरलॉर्ड

1
@ फ़ायरलॉर्ड: आपको शर्तों को एक if/ elseस्टेटमेंट में अलग करना होगा thenऔर fiइसे दोहराने से बचने के लिए किसी फ़ंक्शन में कोड और बीच में रखना होगा। बहुत ही सरल मामलों में आप एक caseस्टेटमेंट का उपयोग कर सकते हैं ;&(बैश 4 में)।
अगली सूचना तक रोक दिया गया।

1
दो वर्ग कोष्ठक का उद्देश्य क्या है?
पीटरचूला


37

/bin/bashनिम्नलिखित का उपयोग करने से काम होगा:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi

8

सावधान रहें यदि आपके स्ट्रिंग चर में स्थान हैं और आप अस्तित्व की जांच करते हैं। उन्हें ठीक से उद्धृत करना सुनिश्चित करें।

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then

1
जब हम डॉलर प्रतीक के बाद घुंघराले कोष्ठक का उपयोग करते हैं !!
YouAreAwesome

6
$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc

2
वह बेकार है। { ;}इसके बजाय इस्तेमाल किया जा सकता है।
phk

2

स्ट्रिंग तुलना के लिए बैश में, आप निम्न तकनीक का उपयोग कर सकते हैं।

if [ $var OP "val" ]; then
    echo "statements"
fi

उदाहरण:

var="something"
if [ $var != "otherthing" ] && [ $var != "everything" ] && [ $var != "allthings" ]; then
    echo "this will be printed"
else
    echo "this will not be printed"
fi

0
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} )
echo $current_usage
critical_usage=6%
warning_usage=3%

if [[ ${current_usage%?} -lt ${warning_usage%?} ]]; then
echo OK current usage is $current_usage
elif [[ ${current_usage%?} -ge ${warning_usage%?} ]] && [[ ${current_usage%?} -lt ${critical_usage%?} ]]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi

3
ढेर अतिप्रवाह में आपका स्वागत है! यह प्रश्न एक स्पष्टीकरण की तलाश में है , केवल काम करने वाले कोड के लिए नहीं। आपका उत्तर प्रश्नकर्ता के लिए कोई अंतर्दृष्टि प्रदान नहीं करता है, और हटाया जा सकता है। कृपया संपादित क्या मनाया लक्षण उत्पन्न व्याख्या करने के लिए।
टोबे स्पाइट

0

आप 2 से अधिक स्थितियों की भी श्रृंखला बना सकते हैं:

if [ \( "$1" = '--usage' \) -o \( "$1" = '' \) -o \( "$1" = '--help' \) ]
then
   printf "\033[2J";printf "\033[0;0H"
   cat << EOF_PRINT_USAGE

   $0 - Purpose: upsert qto http json data to postgres db

   USAGE EXAMPLE:

   $0 -a foo -a bar



EOF_PRINT_USAGE
   exit 1
fi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.