शेल द्वारा सरणी समर्थन के लिए परीक्षण


12

क्या कमांड लाइन पर स्थानीय बॉर्न-जैसे शेल द्वारा सरणी समर्थन के लिए परीक्षण का एक संक्षिप्त तरीका है?

यह हमेशा संभव है:

$ arr=(0 1 2 3);if [ "${arr[2]}" != 2 ];then echo "No array support";fi

या $SHELLशेल संस्करण के लिए परीक्षण :

$ eval $(echo "$SHELL --version") | grep version

और फिर मैन पेज को पढ़ते हुए, मुझे लगता है कि मेरी पहुंच है। (यहां तक ​​कि, लेखन से /bin/bash, मैं मान रहा हूं कि सभी बॉर्न-जैसे गोले लंबे विकल्प को स्वीकार करते हैं --version, जब उदाहरण के लिए ksh के लिए टूट जाता है ।)

मैं एक साधारण परीक्षण की तलाश कर रहा हूं जिसे स्क्रिप्ट की शुरुआत में या इसे कॉल करने से पहले भी उपयोग अनुभाग में अनअटेंड और निगमित किया जा सकता है ।


मुझे लगता है कि आप बॉर्न जैसे गोले को सीमित करना चाहते हैं?
स्टीफन चेज़लस

@ स्टीफनचेज़ेलस: हां, यदि आपका मतलब है (थकावट से नहीं): श, सी, के, टीश, बाश, जेड और करीबी दोस्तों से बना है। मुझे नहीं पता कि यश खुद को इस नक्षत्र में कहां रखता है।
Cbhihe

2
cshबोर्न शेल नहीं है। tcshएक या तो नहीं है (यह cshकुछ कीड़े के साथ तय है)
cas

1
ध्यान दें कि $SHELLउपयोगकर्ता का पसंदीदा शेल है, जैसे $EDITORउसका पसंदीदा टेक्स्ट एडिटर। वर्तमान में चल रहे शेल के साथ इसका बहुत कम संबंध है।
स्टीफन चेज़लस

1
eval$SHELL --versionशेल कोड के आउटपुट का कोई मतलब नहीं है।
स्टीफन चेजलस

जवाबों:


12

मान लें कि आप बॉर्न की तरह गोले (कई अन्य गोले पसंद करने के लिए प्रतिबंधित करना चाहते हैं csh, tcsh, rc, esया fishसमर्थन सरणियों लेकिन एक स्क्रिप्ट के गोले की तरह बॉर्न को एक ही समय में संगत लेखन और उन मुश्किल और आम तौर पर व्यर्थ है के रूप में वे पूरी तरह से अलग और के लिए दुभाषिए हैं असंगत भाषाएं), ध्यान दें कि कार्यान्वयन के बीच महत्वपूर्ण अंतर हैं।

बॉर्न जैसे गोले जो कि ऐरे का समर्थन करते हैं:

  • ksh88(यह पहले लागू करने वाला सरणियाँ है, ksh88 अभी भी kshसबसे पारंपरिक वाणिज्यिक यूनियनों के रूप में पाया जाता है जहां यह इसके लिए आधार भी है sh)

    • सरणियाँ एक आयामी हैं
    • Arrays को परिभाषित किया जाता है set -A array foo barया set -A array -- "$var" ...यदि आप गारंटी नहीं दे सकते हैं कि या के $varसाथ शुरू नहीं होगा ।-+
    • ऐरे सूचकांक शुरू होते हैं 0
    • अलग-अलग सरणी तत्व के रूप में असाइन किए गए हैं a[1]=value
    • सरणियाँ विरल हैं। वह a[5]=fooकाम करेगा भले ही a[0,1,2,3,4]सेट न हो और उन्हें परेशान न करे।
    • ${a[5]}5 इंडिस के तत्व तक पहुंचने के लिए (जरूरी नहीं कि 6 वें तत्व अगर सरणी विरल है)। 5किसी भी गणित अभिव्यक्ति हो सकता है।
    • सरणी का आकार और सबस्क्रिप्ट सीमित है (4096 तक)।
    • ${#a[@]} सरणी में असाइन किए गए तत्व की संख्या है (सबसे बड़ा निर्दिष्ट इंडिस नहीं)।
    • असाइन किए गए ग्राहकों की सूची जानने का कोई तरीका नहीं है (व्यक्तिगत रूप से 4096 तत्वों के परीक्षण के अलावा [[ -n "${a[i]+set}" ]])।
    • $aके रूप में ही है ${a[0]}। यह है कि सरणियाँ किसी भी तरह अतिरिक्त मान देकर स्केलर चर का विस्तार करती हैं।
  • pdkshऔर डेरिवेटिव (यह कई बीएसडी के kshऔर कभी-कभी shके लिए आधार है और ksh93 स्रोत मुक्त होने से पहले केवल ओपनसोर्स ksh कार्यान्वयन था):

    ज्यादातर पसंद है ksh88लेकिन ध्यान दें:

    • कुछ पुराने कार्यान्वयन का समर्थन नहीं किया set -A array -- foo bar, ( --वहाँ की जरूरत नहीं थी)।
    • ${#a[@]}एक प्लस सबसे बड़ा सौंपा सूचकांक का सूचकांक है। ( a[1000]=1; echo "${#a[@]}"आउटपुट 1001 है, भले ही सरणी में केवल एक तत्व हो।
    • नए संस्करणों में, सरणी आकार अब सीमित नहीं है (पूर्णांकों के आकार के अलावा)।
    • के हाल के संस्करणों mkshसे प्रेरित कुछ अतिरिक्त ऑपरेटरों है bash, ksh93या zshकार्य की तरह एक ला a=(x y), a+=(z), ${!a[@]}सौंपा सूचकांक की सूची प्राप्त करने।
  • zshzshसरणियों को आम तौर पर बेहतर तरीके से डिज़ाइन किया जाता है और सबसे अच्छा kshऔर cshसरणियाँ लेते हैं। वे kshमहत्वपूर्ण अंतर के साथ समान हैं :

    • सूचकांक 1 पर शुरू होता है, 0 पर नहीं ( kshअनुकरण को छोड़कर ), यह बॉर्न सरणी (स्थिति पैरामीटर $ @, जो zshकि इसके $ argv सरणी के रूप में भी उजागर होता है) और cshसरणियों के अनुरूप है ।
    • वे सामान्य / स्केलर चर से एक अलग प्रकार हैं। ऑपरेटर उनके लिए अलग तरह से लागू होते हैं और जैसे आप आमतौर पर उम्मीद करते हैं। $aके रूप में ही नहीं है, ${a[0]}लेकिन सरणी के गैर-खाली तत्वों ( "${a[@]}"जैसे सभी तत्वों के लिए ksh) में फैलता है ।
    • वे सामान्य सरणियाँ हैं, विरल सरणियाँ नहीं। a[5]=1काम करता है, लेकिन सभी तत्वों को 1 से 4 तक खाली स्ट्रिंग प्रदान करता है यदि उन्हें असाइन नहीं किया गया है। तो ${#a[@]}(के रूप में ${#a}जो ksh में इंडिस 0 के तत्व का आकार है) सरणी में तत्वों की संख्या और सबसे बड़ा असाइन किया गया मसाला है।
    • सहयोगी सरणियों का समर्थन किया जाता है।
    • एरियर्स के साथ काम करने के लिए ऑपरेटरों की एक बड़ी संख्या का समर्थन किया गया है, यहां सूचीबद्ध करने के लिए बहुत बड़ा है।
    • सरणियों के रूप में परिभाषित किया गया है a=(x y)set -A a x yयह भी काम करता है, लेकिन set -A a -- x yजब तक ksh एमुलेशन ( --zsh एमुलेशन में आवश्यक नहीं है) का समर्थन नहीं किया जाता है।
  • ksh93। (यहाँ नवीनतम संस्करण का वर्णन करते हुए)। ksh93, लंबे समय तक प्रायोगिक अब अधिक से अधिक सिस्टम में पाया जा सकता है कि अब इसे FOSS के रूप में जारी किया गया है। उदाहरण के लिए, यह /bin/sh(जहां यह बॉर्न शेल को प्रतिस्थापित करता है /usr/xpg4/bin/sh, पोसिक्स शेल अभी भी आधारित है ksh88) और kshका Solaris 11। इसके सरणियों का विस्तार और ksh88 है।

    • a=(x y)एक सरणी को परिभाषित करने के लिए इस्तेमाल किया जा सकता है, लेकिन चूंकि a=(...)इसका उपयोग यौगिक चर ( a=(foo=bar bar=baz)) को परिभाषित करने के लिए भी किया जाता है , a=()अस्पष्ट है और एक यौगिक नहीं, बल्कि एक यौगिक चर घोषित करता है।
    • सरणियाँ बहु-आयामी हैं ( a=((0 1) (0 2))) और सरणी तत्व भी यौगिक चर ( a=((a b) (c=d d=f)); echo "${a[1].c}") हो सकते हैं ।
    • एक a=([2]=foo [5]=bar)बार में एक विरल सरणियों को परिभाषित करने के लिए एक वाक्यविन्यास का उपयोग किया जा सकता है।
    • आकार सीमाएं हटा दी गईं।
    • की सीमा तक नहीं zsh, लेकिन बड़ी संख्या में ऑपरेटरों ने सरणियों में हेरफेर करने के लिए समर्थन किया।
    • "${!a[@]}" सरणी सूचकांकों की सूची पुनः प्राप्त करने के लिए।
    • सहयोगी सरणियों को एक अलग प्रकार के रूप में भी समर्थन किया गया है।
  • bashbashGNU परियोजना का खोल है। इसका उपयोग shOS / X के हाल के संस्करणों और कुछ GNU / Linux वितरणों के रूप में किया जाता है। bashसरणियों ज्यादातर का अनुकरण ksh88की कुछ सुविधाओं के साथ लोगों ksh93और zsh

    • a=(x y)समर्थित। समर्थित set -A a x y नहीं हैa=()एक खाली सरणी (कोई यौगिक चर नहीं bash) बनाता है ।
    • "${!a[@]}" सूचकांकों की सूची के लिए।
    • a=([foo]=bar)सिंटैक्स समर्थित है और साथ ही कुछ अन्य से ksh93और zsh
    • हाल के bashसंस्करण भी एक अलग प्रकार के रूप में सहयोगी सरणियों का समर्थन करते हैं।
  • yash। यह अपेक्षाकृत हाल ही में, स्वच्छ, बहु-बाइट से अवगत पोसिक्स श कार्यान्वयन है। व्यापक उपयोग में नहीं। इसके एरे के समान एक और साफ एपीआई हैzsh

    • सरणियाँ विरल नहीं हैं
    • ऐरे सूचकांक 1 से शुरू होते हैं
    • परिभाषित (और घोषित) के साथ a=(var value)
    • arrayअंतर्निहित तत्वों के साथ सम्मिलित, हटाए गए या संशोधित किए गए तत्व
    • array -s a 5 valueयदि उस तत्व को पहले से असाइन नहीं किया गया था, तो 5 वें तत्व को संशोधित करना विफल होगा।
    • सरणी में तत्वों की संख्या है ${a[#]}, ${#a[@]}एक सूची के रूप तत्वों का आकार जा रहा है।
    • सरणियाँ एक अलग प्रकार हैं। a=("$a")तत्वों को जोड़ने या संशोधित करने से पहले आपको एक स्केलर चर को फिर से परिभाषित करने की आवश्यकता है।
    • जब आह्वान किया जाता है तो सरणियों का समर्थन नहीं किया जाता है sh

तो, इससे आप देख सकते हैं कि सरणी समर्थन के लिए पता लगाना, जो आप कर सकते हैं:

if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
   ) > /dev/null 2>&1
then
  array_supported=true
else
  array_supported=false
fi

उन सरणियों का उपयोग करने में सक्षम होने के लिए पर्याप्त नहीं है। आपको संपूर्ण और व्यक्तिगत तत्वों के रूप में सरणियों को निर्दिष्ट करने के लिए रैपर कमांड को परिभाषित करने की आवश्यकता होगी, और सुनिश्चित करें कि आप विरल सरणियों को बनाने का प्रयास नहीं करते हैं।

पसंद

unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
  set -A a -- a b
  case ${a[0]}${a[1]} in
    --) set_array() { eval "shift; set -A $1"' "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=0;;
     a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=1;;
   --a) set_array() { eval "shift; set -A $1"' "$@"'; }
        set_array_element() { eval "$1[\$2]=\$3"; }
        first_indice=0;;
    ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        set_array_element() { eval "$1[\$2]=\$3"; }
        first_indice=0;;
  esac
elif (eval 'a[5]=x') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"$@")'; }
  set_array_element() { eval "$1[\$2]=\$3"; }
  first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"$@")'; }
  set_array_element() {
    eval "
      $1=(\${$1+\"\${$1[@]}"'"})
      while [ "$(($2))" -ge  "${'"$1"'[#]}" ]; do
        array -i "$1" "$2" ""
      done'
    array -s -- "$1" "$((1+$2))" "$3"
   }
  array_elements() { eval "REPLY=\${$1[#]}"; }
  first_indice=1
else
  echo >&2 "Array not supported"
fi

और फिर आप के साथ सरणी तत्वों का उपयोग "${a[$first_indice+n]}"के साथ, पूरी सूची "${a[@]}"और आवरण कार्यों का उपयोग ( array_elements, set_array, set_array_element) (में एक सरणी के तत्वों की संख्या प्राप्त करने $REPLY), एक पूरी या असाइन करने वाले तत्वों के रूप में देता है निर्धारित किया है।

शायद प्रयास के लायक नहीं। मैं perlबॉर्न / POSIX शेल सरणी का उपयोग या सीमा करूँगा "$@":।

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

आप स्थानीय स्कोप (फ़ंक्शन या अनाम फ़ंक्शंस में) zshसरणियों को अधिक कॉन्फ़िगर करने के लिए कॉन्फ़िगर कर सकते हैं ksh

myfunction() {
  [ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
  # use arrays of indice 0 in this function
}

आप अनुकरण भी कर सकते हैं ksh( kshसरणियों और कई अन्य क्षेत्रों के लिए अनुकूलता में सुधार )

myfunction() {
  [ -z "$ZSH_VERSION" ] || emulate -L ksh
  # ksh code more likely to work here
}

मन में है कि और आप के साथ हैं के लिए समर्थन छोड़ करने के लिए तैयार yashहै और ksh88और के पुराने संस्करणों के pdkshडेरिवेटिव, और जब तक आप विरल सरणियों बनाने की कोशिश नहीं करते हैं, तब तक आप लगातार उपयोग करने के लिए सक्षम होना चाहिए:

  • a[0]=foo
  • a=(foo bar)(लेकिन नहीं a=())
  • "${a[#]}", "${a[@]}","${a[0]}"

उन कार्यों में जो हैं emulate -L ksh, जबकि zshउपयोगकर्ता अभी भी आम तौर पर zsh तरह से उसकी / उसकी सरणियों का उपयोग कर रहा है।


7

आप evalसरणी सिंटैक्स आज़माने के लिए उपयोग कर सकते हैं :

is_array_support() (
  eval 'a=(1)'
) >/dev/null 2>&1

if is_array_support; then
  echo support
else
  echo not
fi

2
ksh88सरणियों का समर्थन करता है, लेकिन नहीं a=()। में ksh93, a=()एक यौगिक चर, नहीं एक सरणी जब तक चर एक सरणी के रूप में पहले से घोषित किया गया है की घोषणा की।
स्टीफन चेजलस

2
यह भी ध्यान दें कि सरणी कार्यान्वयन के बीच महत्वपूर्ण अंतर हैं। उदाहरण के लिए, कुछ में 0 (bash, ksh, zsh in ksh emulation) से शुरू होने वाले सरणी सूचकांक हैं, कुछ एक (zsh, yash) से शुरू होते हैं। कुछ सामान्य सरणियाँ / सूचियाँ हैं, कुछ विरल सरणियाँ हैं (ksh या bash में सकारात्मक पूर्णांकों तक सीमित कुंजी के साथ साहचर्य सरणियाँ)।
स्टीफन चेज़लस

में yash, आप ऐसा नहीं करते हैं a[5]=1लेकिनarray -s a 5 1
स्टीफन चेज़लस

@ स्टीफनचेलजैस: पूर्वाग्रहों के लिए धन्यवाद। मेरे मामले में सब कुछ उबलता है कि क्या सरणियों (साहचर्य या नहीं) का समर्थन किया जाता है। इंडेक्स-बेस के बारे में विवरण आसानी से काम किया जा सकता है यहां तक ​​कि एक स्क्रिप्ट में भी अप्राप्य को चलाने के लिए।
Cbhihe

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