मैं दूसरे चर के आधार पर एक चर के लिए अलग-अलग मान कैसे दे सकता हूं?


20

मैं इस शेल स्क्रिप्ट को कैसे छोटा कर सकता हूं?

CODE="A"

if test "$CODE" = "A"
then
 PN="com.tencent.ig"
elif test "$CODE" = "a"
 then
 PN="com.tencent.ig"
elif test "$CODE" = "B"
 then
 PN="com.vng.pubgmobile"
elif test "$CODE" = "b"
 then
 PN="com.vng.pubgmobile"
elif test "$CODE" = "C"
 then
 PN="com.pubg.krmobile"
elif test "$CODE" = "c"
 then
 PN="com.pubg.krmobile"
elif test "$CODE" = "D"
 then
 PN="com.rekoo.pubgm"
elif test "$CODE" = "d"
 then
 PN="com.rekoo.pubgm"
else
 echo -e "\a\t ERROR!"
 echo -e "\a\t CODE KOSONG"
 echo -e "\a\t MELAKUKAN EXIT OTOMATIS"
 exit
fi

2
मुझे लगता है कि यह bashकोड है? या आपके मन में कोई और खोल है?
फ्रेडी

3
भविष्य में FYI करें, मैं "com.hello.world" जैसी कुछ सामान्य चीज़ों के साथ व्यक्तिगत जानकारी जैसे URL और अन्य चीज़ों को बदलने की सलाह दूंगा।
ट्रेवर बॉयड स्मिथ

1
@IISomeOneII आपको कोडगॉल्फ से पूछना चाहिए। इसके बजाय: P
mackycheese21

3
@Trevor, मैं सलाह देते हैं example.org, example.net, आदि के रूप में विशेष रूप से इन डोमेन आरएफसी 2606 में इस उद्देश्य के लिए आरक्षित हैं और कभी नहीं असली संस्थाओं के लिए इस्तेमाल किया जाएगा।
टॉबी स्पाइट नाइट

2
@TrevorBoydSmith सेकिंग टॉबी की com.example आदि की सिफारिश, क्योंकि "hello.com" Google के स्वामित्व में है।
डेविड कॉनराड

जवाबों:


61

एक caseकथन (पोर्टेबल, किसी भी shतरह के शेल में काम करता है ) का उपयोग करें:

case "$CODE" in
    [aA] ) PN="com.tencent.ig" ;;
    [bB] ) PN="com.vng.pubgmobile" ;;
    [cC] ) PN="com.pubg.krmobile" ;;
    [dD] ) PN="com.rekoo.pubgm" ;;
    * ) printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
        exit 1 ;;
esac

मैं सभी बड़े अक्षरों (जैसे CODE) से आपके चर नामों को कुछ कम- या मिश्रित-मामले (जैसे codeया Code) में बदलने की सलाह दूंगा । ऐसे कई ऑल-कैप नाम हैं जिनके विशेष अर्थ हैं, और उनमें से किसी एक को दुर्घटना से फिर से उपयोग करना परेशानी का कारण बन सकता है।

अन्य नोट: मानक सम्मेलन "मानक आउटपुट" के बजाय "मानक त्रुटि" के लिए त्रुटि संदेश भेजना है; >&2रीडायरेक्ट करता है। इसके अलावा, यदि कोई स्क्रिप्ट (या प्रोग्राम) विफल हो जाता है, तो एक गैर-स्थिति ( exit 1) के साथ बाहर निकलना सबसे अच्छा है , इसलिए कोई भी कॉलिंग संदर्भ बता सकता है कि क्या गलत है। यह भी विभिन्न समस्याओं का संकेत करने के लिए (के "बाहर निकलें कोड" खंड देखें विभिन्न स्थितियों का उपयोग करना संभव है आदमी पेज एक अच्छा उदाहरण के लिए)। (यहाँ सुझाव के लिए स्टीफन चेज़लस और मोंटी हार्डर को श्रेय।)curl

मैं printfइसके बजाय echo -e(और echo -n) की सलाह देता हूं , क्योंकि यह OSes, संस्करणों, सेटिंग्स, आदि के बीच अधिक पोर्टेबल है। मैंने एक बार अपनी स्क्रिप्ट को तोड़ दिया था क्योंकि एक OS अपडेट में विभिन्न विकल्पों के साथ संकलित बैश का एक संस्करण शामिल था, जो कि echoव्यवहार में कैसे बदला गया ।

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


5
@IISomeOneII जो *(और त्रुटि प्रिंट करेगा) के रूप में गिना जाएगा - पैटर्न [aA]"ए" या "ए" से मेल खाता है, लेकिन दोनों एक साथ नहीं।
गॉर्डन डेविसन

6
यह करने के लिए बिल्कुल सही तरीका है, ठीक वाइल्डकार्ड के ठीक नीचे, इसके उत्पादन को स्टोडर पर पुनर्निर्देशित करने और गैर-शून्य निकास मान उत्पन्न करने के लिए। केवल एक चीज जिसे बदलने की आवश्यकता हो सकती है, वह है निकास मूल्य, क्योंकि लौटने के लिए एक से अधिक त्रुटि हो सकती है। एक बड़ी स्क्रिप्ट में, एक खंड हो सकता है (शायद किसी अन्य फ़ाइल से खट्टा) जो निकास घाटी को परिभाषित करता है readonly Exit_BadCode=1ताकि वह इसके exit $Exit_BadCodeबजाय कह सके ।
मोंटी हार्डर

2
हाल ही में एक पार्टी के साथ जा रहा है, तो का उपयोग case "${CODE,}" in, इसलिए सशर्त, में से प्रत्येक के बस हो जाता है कि a), b)आदि
स्टीव

2
@MontyHarder यह निर्भर करता है। यदि इन कोडों में से कुछ सौ हैं, प्रत्येक एक स्ट्रिंग के अनुरूप है, तो एक और दृष्टिकोण बेहतर हो सकता है। हाथ में सटीक मुद्दे के लिए, यह पर्याप्त है।
Kusalananda

2
@MontyHarder क्षमा करें, मुझे स्पष्ट होना चाहिए था। "कोड" से मेरा मतलब था $CODE। मैं हमेशा "बाहर निकलने की स्थिति" कहता हूं, कभी भी "कोड" नहीं। यदि स्क्रिप्ट को स्ट्रिंग्स को संदर्भित करने के लिए कई सैकड़ों कुंजियों का उपयोग करने की आवश्यकता होती है , तो एक caseकथन का उपयोग करना अस्पष्ट हो जाता है।
Kusalananda

19

मान लें कि आप bashरिलीज़ 4.0 या नए का उपयोग कर रहे हैं ...

CODE=A

declare -A domain

domain=(
   [a]=com.tencent.ig
   [b]=com.vng.pubgmobile
   [c]=com.pubg.krmobile
   [d]=com.rekoo.pubgm
)

PN=${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

कोड में, मैं एक साहचर्य सरणी को परिभाषित करता हूं जिसमें सभी डोमेन नाम शामिल हैं, प्रत्येक एक अक्षर से कम केस की कुंजी के साथ जुड़ा हुआ है।

$PNचर डोमेन नाम कम मामलों के लिए इसी असाइन किया गया है $CODEमूल्य ( ${CODE,,}रिटर्न का मूल्य $CODEकेवल लोअर केस अक्षरों में बदल गया) इस सरणी से, लेकिन अगर $CODEमें एक मान्य प्रविष्टि के अनुरूप नहीं है domainसूची, यह एक साथ स्क्रिप्ट बाहर निकालता है त्रुटि।

${variable:?error message}पैरामीटर प्रतिस्थापन के मूल्य के विस्तार होगा $variable(कोड में उपयुक्त डोमेन), लेकिन त्रुटि संदेश के साथ स्क्रिप्ट से बाहर निकल जाएगा यदि मान रिक्त उपलब्ध नहीं है। आपको अपने कोड के अनुसार त्रुटि संदेश का बिल्कुल स्वरूपण नहीं मिलता है, लेकिन यदि यह अमान्य है तो यह अनिवार्य रूप से व्यवहार करेगा $CODE:

$ bash script.sh
script.sh: line 12: domain[${CODE,,}]: ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS

यदि आप कैरेक्टर काउंट की परवाह करते हैं, तो हम इसे और छोटा कर सकते हैं:

CODE=A
declare -A domain=( [a]=tencent.ig [b]=vng.pubgmobile [c]=pubg.krmobile [d]=rekoo.pubgm )
PN=com.${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

अनावश्यक न्यूलाइन्स को हटाने के अलावा, मैंने com.प्रत्येक डोमेन से हटा दिया है (यह इसके बजाय असाइनमेंट में जोड़ा गया है PN)।

ध्यान दें कि ऊपर दिया गया सभी कोड मल्टी-कैरेक्टर वैल्यू के लिए भी काम करेगा $CODE(यदि domainएरे में इन के लिए लोअर-केस कीज़ मौजूद हैं )।


यदि $CODEइसके बजाय एक संख्यात्मक (शून्य-आधारित) सूचकांक था, तो यह कोड को थोड़ा सरल करेगा:

CODE=0

domain=( com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm )
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

यह अतिरिक्त रूप domainसे सहायक फाइल से सरणी को पढ़ना आसान बना देगा, जिसमें प्रति पंक्ति एक प्रविष्टि है:

CODE=0

readarray -t domain <domains.txt
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

1
@IISomeOneII का declare -A domainकहना है कि domainएक साहचर्य सरणी ("हैश") चर होना चाहिए।
Kusalananda

1
@ इस्साक अब तुमसे और अलग है। सर उठाने के लिए धन्यवाद।
Kusalananda

1
Zsh या ksh93 का उपयोग करना बेहतर होगा। बैश के लिए, आपको हाल के संस्करण की आवश्यकता होगी और यह रिक्त मानों के लिए विफल होगा $CODE
स्टीफन चेजालस

1
@ StéphaneChazelas हाँ, यदि आप $CODEपरेशान या खाली हैं, तो एक खराब सरणी सबस्क्रिप्ट के बारे में एक अतिरिक्त त्रुटि संदेश प्राप्त होगा , लेकिन यह उसके बाद भी सही कस्टम त्रुटि संदेश उत्पन्न करेगा।
Kusalananda

1
@ कुसलानंद एक नई (वैध POSIX) स्क्रिप्ट पोस्ट की गई। त्रुटि के बिना जाँच बहुत कम है।
इसहाक

11

यदि आपका शेल ऐरे की अनुमति देता है, तो सबसे छोटा उत्तर बश में इस उदाहरण की तरह होना चाहिए:

declare -A site
site=( [a]=com.tencent.ig [b]=com.vng.pubgmobile [c]=com.pubg.krmobile [d]=com.rekoo.pubgm )

pn=${site[${code,}]}

यह मानते हुए कि $codeकेवल एक, बी, सी या डी हो सकता है।
यदि नहीं, तो एक परीक्षण जोड़ें:

case ${site,} in
    a|b|c|d)        pn=${site[${code,}]};;
    *)              pn="default site"
                    printf '\a\t %s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS'
                    exit 1
                    ;;
esac

यदि इनपुट A है तो क्या यह उस स्क्रिप्ट पर काम करेगा? माफ़
कीजियेगा

2
हां, विस्तार ${var,}पहले वर्ण के निचले भाग को परिवर्तित करता है ${var}। @IISomeOneII
इसहाक

1
${var,}हालांकि बैश-विशिष्ट प्रतीत होता है। मुझे लगता है कि साहचर्य सरणी ksh और zsh में भी काम करेगी
ilkachachu

@ilkachachu हाँ, दोनों मायने में सही है।
इसहाक

हर कोई, यहाँ अच्छे लोगों के बहुत सारे everyone
IISomeOneII

3

मैं इस उत्तर को एक अलग दिशा में ले जा रहा हूं। अपने डेटा को स्क्रिप्ट में कोड करने के बजाय, उस डेटा को एक अलग डेटा फ़ाइल में डालें, फिर फ़ाइल को खोजने के लिए कोड का उपयोग करें:

$ cat names.cfg 
a com.tencent.ig
b com.vng.pubgmobile
c com.pubg.krmobile
d com.rekoo.pubgm

$ cat lookup.sh
PN=$(awk -v code="${1:-}" 'tolower($1) == tolower(code) { print $2; }' names.cfg)
if [ -z "${PN}" ]; then
  printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
  exit 1
fi
echo "${PN}"

$ bash lookup.sh A
com.tencent.ig
$ bash lookup.sh a
com.tencent.ig
$ bash lookup.sh x
    ERROR!
    CODE KOSONG
    MELAKUKAN EXIT OTOMATIS

इन चिंताओं को अलग करने से कुछ लाभ हैं:

  • कोड लॉजिक के आसपास काम किए बिना आसानी से और सरलता से डेटा जोड़ें और निकालें।
  • अन्य कार्यक्रम डेटा का पुन: उपयोग कर सकते हैं, जैसे किसी विशेष उप डोमेन में कितने मैच गिन रहे हैं।
  • यदि आपके पास डेटा की एक विशाल सूची है, तो आप इसे डिस्क पर सॉर्ट कर सकते हैं और lookइसे कुशलतापूर्वक बाइनरी सर्च करने के लिए उपयोग कर सकते हैं (लाइन-दर-लाइन grepया लाइन के बजाय awk)

1
यदि आप इस तरह से जाते हैं, तो आपको अभी भी PNसही मूल्य पर सेट होने की व्यवस्था करने की आवश्यकता है ।
इलकाचू

1
@ तिलकचु मेला बिंदु मुझे ओपी में याद किया। सही किया।
बिशप

2
कोड से डेटा को अलग करने के लिए +1।
अरप

1

आप मूल्यों को अनुक्रमित करने के लिए अक्षरों का उपयोग कर रहे हैं, यदि आप संख्याओं का उपयोग करते हैं, तो यह उतना ही सरल हो जाता है:

code=1
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

eval pn\=\${"$code"}

यह पोर्टेबल शेल कोड है, अधिकांश शेल पर काम करेगा।
बैश के लिए आप का उपयोग कर सकते हैं: pn=${!code}या बैश / ksh / zsh उपयोग के लिए pn=${@:code:1}:।

पत्र

यदि आपको उपयोगकर्ता पत्र (ए से जेड तक, या ए से जेड तक) होना चाहिए तो उन्हें एक सूचकांक में परिवर्तित किया जाना चाहिए:

code=a                              # or A, B, C, ... etc.
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code")|32)-96  ))}\"

प्रत्येक भाग के इरादे और अर्थ को स्पष्ट करने के लिए एक लंबे कोड में:

code=A

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

asciival=$(( $(printf '%d' "'$code") ))      # byte value of the ASCII letter.
upperval=$(( asciival |  32 ))               # shift to uppercase.
indexval=$(( upperval -  96 ))               # convert to an index from a=1.
eval arg\=\"\$\{$indexval\}\"                # the argument at such index.

यदि आपको लोअरकेस मान में कनवर्ट करने की आवश्यकता है, तो उपयोग करें: $(( asciival & ~32 ))(सुनिश्चित करें कि एससीआई मूल्य का बिट 6 परेशान है)।

एरर कोड

आउटपुट जो आपकी स्क्रिप्ट को एक त्रुटि पर प्रिंट करता है वह काफी लंबा (और विशेष) है।
इससे निपटने के लिए सबसे बहुमुखी तरीका एक फ़ंक्शन को परिभाषित करना है:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

और फिर उस फ़ंक्शन को उस विशिष्ट संदेश के साथ कॉल करें जिसकी आपको आवश्यकता है।

errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS"

ध्यान दें कि परिणामी निकास मान द्वारा दिया गया है exitcode(उदाहरण यहाँ 27 है)।

एक पूर्ण स्क्रिप्ट (त्रुटि जाँच के साथ) तब बन जाती है:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; exit "$exitcode"; }

code=${1:-A}

case "$code" in 
    [a-d]|[A-D]) : ;;
    *)           errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS" ;;
esac

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code") & ~32) - 64  ))}\"

printf 'Code=%s Argument=%s\n' "$code" "$pn"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.