क्या बैश / बॉर्न में "इन" ऑपरेटर है?


17

मैं एक "इन" ऑपरेटर की तलाश कर रहा हूं जो कुछ इस तरह से काम करता है:

if [ "$1" in ("cat","dog","mouse") ]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

यह स्पष्ट रूप से कई "या" परीक्षणों का उपयोग करते हुए, कहने की तुलना में बहुत छोटा बयान है।

जवाबों:


31

आप उपयोग कर सकते हैं case...esac

$ cat in.sh 
#!/bin/bash

case "$1" in 
  "cat"|"dog"|"mouse")
    echo "dollar 1 is either a cat or a dog or a mouse"
  ;;
  *)
    echo "none of the above"
  ;;
esac

पूर्व।

$ ./in.sh dog
dollar 1 is either a cat or a dog or a mouse
$ ./in.sh hamster
none of the above

साथ ksh, bash -O extglobया zsh -o kshglob, आप भी एक विस्तारित ग्लोब पैटर्न इस्तेमाल कर सकते हैं:

if [[ "$1" = @(cat|dog|mouse) ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi

के साथ bash, ksh93या zsh, आप भी एक नियमित अभिव्यक्ति तुलना का उपयोग कर सकते हैं:

if [[ "$1" =~ ^(cat|dog|mouse)$ ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi

डबल ब्रैकेट का कोई कारण? एक बार फिर धन्यवाद!
मर्जज्विपर

1
@mrjayviper डबल ब्रैकेट एक विस्तारित परीक्षण निर्माण हैं - AFAIK द रेगेक्स ऑपरेटर =~POSIX एकल-ब्रैकेट परीक्षण के अंदर वैध नहीं है
Steeldriver

1
@steeldriver केवल [POSIX है, लेकिन [[पार्टी की विस्तारित सुविधा, ksh (जाहिरा तौर पर यह वहाँ से उत्पन्न है, और zsh है। caseउदाहरण सभी के अधिकांश POSIX, हालांकि है
सर्गी Kolodyazhnyy

2
@ स्टीफनचेज़ेलस कम से कम 4.1-अल्फा के बाद से स्पष्ट रूप से एक्सग्लॉग सेट करने की कोई आवश्यकता नहीं है। बैश परिवर्तन से : एस। फोर्स अस्थायी रूप से एक्सग्लोब पर जब पैटर्न तर्क को पार्स करने के लिए == और! = ऑपरेटर्स के लिए [[कमांड, अनुकूलता के लिए।
इसहाक

@steeldriver $ 1 case "$1" inको उद्धृत करने की आवश्यकता नहीं है, कोई शब्द नहीं बंट रहा है और न ही pathname विस्तार उस टोकन में किया जाता है।
इसहाक

9

बैश में "इन" टेस्ट नहीं है, लेकिन रीजेक्स टेस्ट है (बॉर्न में नहीं):

if [[ $1 =~ ^(cat|dog|mouse)$ ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

और आमतौर पर एक चर का उपयोग करते हुए लिखा जाता है (उद्धृत के साथ कम समस्याएं):

regex='^(cat|dog|mouse)$'

if [[ $1 =~ $regex ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

पुराने बॉर्न शेल के लिए आपको एक केस मैच का उपयोग करने की आवश्यकता है:

case $1 in
    cat|dog|mouse)   echo "dollar 1 is either a cat or a dog or a mouse";;
esac

यह मेरे लिए स्वीकृत उत्तर है।
नम जी वीयू

6

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

यह केवल शाब्दिक स्ट्रिंग से मेल खाएगा cat|dog|mouse:

patt='cat|dog|mouse'
case $1 in 
        $patt) echo "$1 matches the case" ;; 
esac

हालाँकि, आप नियमित अभिव्यक्ति मैच के साथ एक चर का उपयोग कर सकते हैं। जब तक वैरिएबल को उद्धृत नहीं किया जाता है, तब तक किसी भी रेगेक्स ऑपरेटर के पास इसके विशेष अर्थ होते हैं।

patt='cat|dog|mouse'
if [[ "$1" =~ ^($patt)$ ]]; then
        echo "$1 matches the pattern"
fi

आप साहचर्य सरणियों का भी उपयोग कर सकते हैं। यह जांचना कि क्या एक कुंजी मौजूद है, एक inऑपरेटर के पास निकटतम चीज है जो बैश देता है। हालांकि वाक्य रचना थोड़ा बदसूरत है:

declare -A arr
arr[cat]=1
arr[dog]=1
arr[mouse]=1

if [ "${arr[$1]+x}" ]; then
        echo "$1 is in the array"
fi

( ${arr[$1]+x}फैलता करने के लिए xकरता है, तो arr[$1]सेट कर दिया जाता है, अन्यथा खाली करें। )


5

आप एक परीक्षण में एक बयान का उपयोग कर सकते हैं , लेकिन कोड थोड़ा बालों वाला लगेगा:caseif

if case "$1" in (cat|dog|mouse) true ;; (*) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

या थोड़ा कम,

if ! case "$1" in (cat|dog|mouse) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

यह caseखंड के लिए मिलान करने के लिए सिर्फ एक खंड का उपयोग कर रहा है if। यह एक अनावश्यक सच / गलत परीक्षण पेश करता है।

यह सिर्फ उपयोग करने के लिए बेहतर है case:

case "$1" in
    cat|dog|mouse)
        printf '"%s" is one of cat, dog or mouse\n' "$1"
        ;;
    *)
        printf '"%s" is unknown\n' "$1"
esac

ऐसा न करें:

is_one_of () {
    eval "case $1 in ($2) return 0; esac"
    return 1
}

if is_one_of "$1" 'cat|dog|mouse'; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

या यह:

is_one_of () (
    word=$1
    shift
    IFS='|'
    eval "case $word in ($*) return 0; esac"
    return 1
)

if is_one_of "$1" cat dog mouse; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

... क्योंकि आप सिर्फ अधिक खतरनाक क्रॉफ्ट जोड़ रहे हैं, सिर्फ ifएक पूरी तरह से उचित caseबयान के स्थान पर अपने कोड में एक बयान का उपयोग करने में सक्षम होने के लिए ।


क्या यह बेहतर नहीं होगा कि फंक्शन कॉल में केस को विभाजित किया जाए और यदि स्टेटमेंट के अंदर एक्जिट स्टेटस का मूल्यांकन किया जाए?
सर्गी कोलोडियाज़नी

@SergiyKolodyazhnyy और पैटर्न फ़ंक्शन के लिए एक तर्क है? यह उस मामले में evalएक caseबयान करना होगा, और यह त्रुटियों के लिए और भी अधिक प्रवण होगा।
Kusalananda

इस मामले में सरल पैटर्न है, प्रत्येक को कार्य करने और करने के लिए स्थितीय पैरामीटर के रूप में पारित किया जा सकता है "$1"|"$2"|"$3"। इसके अलावा unix.stackexchange.com/a/234415/85039 लेकिन हाँ, यह थोड़ा बालों वाला है।
सेर्गेई कोलोडियाज़नी

4

grep दृष्टिकोण।

if echo $1 | grep -qE "^(cat|dog|mouse)$"; then 
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
  • -qस्क्रीन पर किसी भी आउटपुट से बचने के लिए (टाइप करने के लिए तेज >/dev/null)।
  • -Eविस्तारित नियमित अभिव्यक्ति (cat|dog|mouse)पहलुओं के लिए इसकी आवश्यकता होती है।
  • ^(cat|dog|mouse)$^बिल्ली, कुत्ते या माउस ( (cat|dog|mouse)) के साथ शुरू होने वाली किसी भी रेखा से मेल खाता है (पंक्ति के अंत के बाद $) ( )
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.