मैं मामले की स्थिति के रूप में एक चर का उपयोग कैसे कर सकता हूं?


17

मैं एक वैरिएबल का उपयोग करने की कोशिश कर रहा हूं जिसमें |एक caseस्टेटमेंट टेस्ट के साथ अलग-अलग स्ट्रिंग्स शामिल हैं । उदाहरण के लिए:

string="\"foo\"|\"bar\""
read choice
case $choice in
    $string)
        echo "You chose $choice";;
    *)
        echo "Bad choice!";;
esac

मैं कथन के पहले भाग को टाइप fooया barनिष्पादित करने में सक्षम होना चाहता हूं case। हालांकि, दोनों fooऔर barमुझे दूसरे के लिए ले:

$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!

के "$string"बजाय का उपयोग कर $stringकोई फर्क नहीं पड़ता। न ही उपयोग करता है string="foo|bar"

मुझे पता है कि मैं इसे इस तरह से कर सकता हूं:

case $choice in
    "foo"|"bar")
        echo "You chose $choice";;
    *)
        echo "Bad choice!";;
esac

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


2
मैं इसे वास्तविक उत्तर के रूप में सुझाव देने के लिए खुद को नहीं ला सकता, लेकिन जब से किसी और ने इसका उल्लेख नहीं किया है, आप केस स्टेटमेंट को एक में लपेट सकते हैंeval , $ पसंद से बच सकते हैं, परेंस, तारांकन, अर्धविराम और नईलाइन्स। बदसूरत, लेकिन यह "काम करता है"।
जेफ स्कालर

@JeffSchaller - यह बहुत बुरा विचार नहीं है, और शायद इस मामले में सिर्फ टिकट है। मैंने इसकी सिफारिश करने पर भी विचार किया, लेकिन readबिट ने मुझे रोक दिया। मेरी राय में उपयोगकर्ता इनपुट सत्यापन, जो कि ऐसा प्रतीत होता है, caseपैटर्न मूल्यांकन सूची के शीर्ष पर नहीं होना चाहिए, और बल्कि *डिफ़ॉल्ट पैटर्न के लिए नीचे झुका होना चाहिए, ताकि केवल वहां पहुंचने वाले परिणाम स्वीकार्य हो जाएं। फिर भी, क्योंकि यह मुद्दा पार्स / विस्तार आदेश है, तो दूसरे मूल्यांकन के लिए क्या कहा जा सकता है।
mikeserv

जवाबों:


14

बैश मैनुअल में कहा गया है:

मामले में शब्द [[(] पैटर्न [| पैटर्न] ...) सूची ;; ] ... एसैक

जांच किए गए प्रत्येक पैटर्न को टिल्ड विस्तार, पैरामीटर और चर विस्तार, अंकगणितीय प्रतिस्थापन, कमांड प्रतिस्थापन और प्रक्रिया प्रतिस्थापन का उपयोग करके विस्तारित किया जाता है।

कोई «पथनाम विस्तार»

इस प्रकार: «पथनाम विस्तार» के साथ एक पैटर्न का विस्तार नहीं किया जाता है।

इसलिए: एक पैटर्न नहीं हो सकता है "|" के भीतर। केवल: दो पैटर्न "|" के साथ जुड़ सकते हैं।

यह काम:

s1="foo"; s2="bar"    # or even s1="*foo*"; s2="*bar*"

read choice
case $choice in
    $s1|$s2 )     echo "Two val choice $choice"; ;;  # not "$s1"|"$s2"
    * )           echo "A Bad  choice! $choice"; ;;
esac

«विस्तारित ग्लोबिंग» का उपयोग करना

हालाँकि, «Pathname विस्तार» नियमों का उपयोग करके wordमिलान किया जाता patternहै।
और «विस्तारित ग्लोबिंग» यहां , यहां और, यहां वैकल्पिक ("|") पैटर्न के उपयोग की अनुमति देता है।

यह भी काम करता है:

shopt -s extglob

string='@(foo|bar)'

read choice
    case $choice in
        $string )      printf 'String  choice %-20s' "$choice"; ;;&
        $s1|$s2 )      printf 'Two val choice %-20s' "$choice"; ;;
        *)             printf 'A Bad  choice! %-20s' "$choice"; ;;
    esac
echo

स्ट्रिंग सामग्री

अगली टेस्ट स्क्रिप्ट से पता चलता है कि पैटर्न सभी रेखाओं से मेल खाता है, जिसमें fooया barकहीं भी है '*$(foo|bar)*'या दो चर हैं $s1=*foo*और$s2=*bar*


परीक्षण स्क्रिप्ट:

shopt -s extglob    # comment out this line to test unset extglob.
shopt -p extglob

s1="*foo*"; s2="*bar*"

string="*foo*"
string="*foo*|*bar*"
string='@(*foo*|*bar)'
string='*@(foo|bar)*'
printf "%s\n" "$string"

while IFS= read -r choice; do
    case $choice in
        "$s1"|"$s2" )   printf 'A first choice %-20s' "$choice"; ;;&
        $string )   printf 'String  choice %-20s' "$choice"; ;;&
        $s1|$s2 )   printf 'Two val choice %-20s' "$choice"; ;;
        *)      printf 'A Bad  choice! %-20s' "$choice"; ;;
    esac
    echo
done <<-\_several_strings_
f
b
foo
bar
*foo*
*foo*|*bar*
\"foo\"
"foo"
afooline
onebarvalue
now foo with spaces
_several_strings_

9

आप extglobविकल्प का उपयोग कर सकते हैं :

shopt -s extglob
string='@(foo|bar)'

दिलचस्प; @(foo|bar)की तुलना में क्या खास बनाता है foo|bar? दोनों मान्य प्रतिमान हैं जो वस्तुतः टाइप किए जाने पर समान काम करते हैं।
चेप्टर

4
आह बुरा न मानें। |में पैटर्न का हिस्सा नहीं है foo|bar, यह caseएक खंड में कई पैटर्न की अनुमति देने के लिए वाक्यविन्यास का हिस्सा है । हालांकि विस्तारित पैटर्न | का हिस्सा है।
13

3

आपको दो चर की आवश्यकता है caseक्योंकि पैटर्न के विस्तार से पहले या |पाइप को पार्स किया जाता है।

v1=foo v2=bar

case foo in ("$v1"|"$v2") echo foo; esac

foo

वैरिएबल में शेल पैटर्न को अलग-अलग तरीके से संभाला जाता है, जब उद्धृत या अछूता हो:

q=?

case a in
("$q") echo question mark;;
($q)   echo not a question mark
esac

not a question mark

-1

यदि आप एक डैश-संगत कार्य चाहते हैं, तो आप लिख सकते हैं:

  string="foo|bar"
  read choice
  awk 'BEGIN{
   n=split("'$string'",p,"|");
   for(i=1;i<=n;i++)
    if(system("\
      case \"'$choice'\" in "p[i]")\
       echo \"You chose '$choice'\";\
       exit 1;;\
      esac"))
     exit;
   print "Bad choice"
  }'

स्पष्टीकरण: awk का उपयोग "स्ट्रिंग" को विभाजित करने और प्रत्येक भाग को अलग से परीक्षण करने के लिए किया जाता है। यदि "पसंद" वर्तमान में परीक्षण किए गए भाग p [i] से मेल खाता है, तो awk- कमांड "11 से बाहर निकलें" पंक्ति 11 में समाप्त हो जाएगी। बहुत परीक्षण के लिए, शेल के "केस" का उपयोग किया जाता है (एक 'सिस्टम-कॉल के भीतर) , टेर्डन द्वारा पूछा गया। यह संभावित परीक्षण- "स्ट्रिंग" को उदाहरण के लिए "फू * | बार" में संशोधित करने की संभावना रखता है ताकि "फू" ("खोज पैटर्न") के लिए भी मिलान किया जा सके, क्योंकि शेल का "केस" अनुमति देता है। यदि इसके बजाय आप नियमित अभिव्यक्ति पसंद करेंगे, तो आप "सिस्टम" को छोड़ सकते हैं और इसके बजाय awk के "~" या "मिलान" का उपयोग कर सकते हैं।


प्रिय downvoter, मैं बेहतर तरीके से सीख सकता हूं कि बेकार समाधान उम्मीदवारों से कैसे बचा जाए यदि आप मुझे आपके डाउनवोट का कारण बताएंगे।
जेराल्ड स्कैड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.