बैश में पैरामीटर के रूप में सरणियों को पास करना


188

मैं एक बैश फ़ंक्शन के पैरामीटर के रूप में एक सरणी कैसे पारित कर सकता हूं?

नोट: स्टैक ओवरफ्लो पर यहां कोई जवाब नहीं मिलने के बाद, मैंने अपना कुछ कच्चा समाधान खुद पोस्ट किया। यह केवल एक एरे पास होने की अनुमति देता है, और यह पैरामीटर सूची का अंतिम तत्व है। दरअसल, यह एरे को बिल्कुल नहीं पास कर रहा है, बल्कि इसके तत्वों की एक सूची है, जिसे आरएफ़ंक्शन () नाम से एक एरे में इकट्ठा किया जाता है, लेकिन यह मेरे लिए काम करता है। यदि कोई बेहतर तरीका जानता है, तो उसे यहां जोड़ने के लिए स्वतंत्र महसूस करें।


1
यहां आपके पास अच्छे संदर्भ और उदाहरण के टन हैं।
आर्टेम बार्गर

16
इर्रर ... एक ही मिनट के भीतर पांच साल पुराने सवाल पर तीन डाउनवोट?
देवसोलर

जवाबों:


219

आप इस तरह से कुछ का उपयोग करते हुए तर्क के रूप में कई सरणियों को पारित कर सकते हैं :

takes_ary_as_arg()
{
    declare -a argAry1=("${!1}")
    echo "${argAry1[@]}"

    declare -a argAry2=("${!2}")
    echo "${argAry2[@]}"
}
try_with_local_arys()
{
    # array variables could have local scope
    local descTable=(
        "sli4-iread"
        "sli4-iwrite"
        "sli3-iread"
        "sli3-iwrite"
    )
    local optsTable=(
        "--msix  --iread"
        "--msix  --iwrite"
        "--msi   --iread"
        "--msi   --iwrite"
    )
    takes_ary_as_arg descTable[@] optsTable[@]
}
try_with_local_arys

गूंजेंगे:

sli4-iread sli4-iwrite sli3-iread sli3-iwrite  
--msix  --iread --msix  --iwrite --msi   --iread --msi   --iwrite

संपादित करें / नोट्स: (नीचे टिप्पणी से)

  • descTableऔर optsTableनाम के रूप में पारित किए जाते हैं और फ़ंक्शन में विस्तारित होते हैं। इस प्रकार कोई $जरूरत नहीं है जब मापदंडों के रूप में दिया जाता है।
  • ध्यान दें कि यह अभी भी साथ descTableपरिभाषित किया जा रहा है आदि के साथ भी काम करता हैlocal , क्योंकि स्थानीय लोग उन कार्यों के लिए दिखाई देते हैं जिन्हें वे कहते हैं।
  • !में ${!1}आर्ग 1 चर फैलता है।
  • declare -a बस अनुक्रमित सरणी को स्पष्ट करता है, यह कड़ाई से आवश्यक नहीं है।

14
एक बात का ध्यान रखें कि यदि मूल सरणी विरल है, तो प्राप्त फ़ंक्शन के सरणी में समान सूचक नहीं होंगे।
अगली सूचना तक रोक दिया गया।

13
यह शानदार है, लेकिन क्या केन या कोई व्यक्ति ऐसी कुछ चीजों की व्याख्या कर सकता है जो मुझे इस बारे में बताती हैं कि यह क्यों काम करता है: 1 - मैंने सोचा होगा कि descTable और optsTable को फ़ंक्शन तर्कों के रूप में पारित होने पर $ के साथ उपसर्ग करना होगा। 2 - "लेता है ..." की पहली पंक्ति में, एक स्पष्ट सरणी घोषणा की आवश्यकता क्यों है? 3 - और क्या करता है! अभिव्यक्ति $ {! 1} में है, और क्यों [@] की आवश्यकता नहीं है या यहां तक ​​कि अनुमति नहीं है? - यह काम करता है, और मेरे परीक्षण के आधार पर इन सभी विवरणों की आवश्यकता प्रतीत होती है, लेकिन मैं यह समझना चाहूंगा कि क्यों!
जनवरी हेटिच

8
1: descTable और optsTable को केवल नामों के रूप में पारित किया जाता है, इस प्रकार कोई $ नहीं है, उन्हें केवल तथाकथित फ़ंक्शन 2 में विस्तारित किया जाएगा: पूरी तरह से निश्चित नहीं है, लेकिन मुझे लगता है कि यह वास्तव में आवश्यक नहीं है 3: द! उपयोग किया जाता है क्योंकि फ़ंक्शन को दिए गए मापदंडों को दो बार विस्तारित करने की आवश्यकता होती है: $ 1 "descTable [@]" तक फैलता है, और इसे "$ {descTable [@]}" तक विस्तारित किया जाना चाहिए। $ {! 1} सिंटैक्स बस यही करता है।
एल्मर जेंडर

8
मुझे नहीं लगता कि "घोषित-ए" भाग आवश्यक है। कोष्ठक का अस्तित्व पहले से ही एक सरणी के रूप में असाइनमेंट के एलएचएस को परिभाषित करता है।
एरिक एरोनेस्टी

3
इस जवाब ने मुझे अभी एक मुद्दे को हल करने में मदद की। हालाँकि, मैं अपनी मशीन पर (bash 4.3.42 का उपयोग करके) "$ {! 1}" और "$ {! 2}" उद्धरण देना चाहता था। यदि आप नहीं करते हैं, तो मूल सरणी का मान एक स्ट्रिंग के रूप में पढ़ा जाता है और क्रमशः argAry1 [0] और argAry2 [0] को सौंपा जाता है, मूल रूप से सरणी संरचना खो जाती है।
user.friendly

85

नोट: यह कुछ कच्चा समाधान है जिसे मैंने खुद पोस्ट किया था, स्टैक ओवरफ्लो पर यहां कोई जवाब नहीं मिलने के बाद। यह केवल एक एरे पास होने की अनुमति देता है, और यह पैरामीटर सूची का अंतिम तत्व है। दरअसल, यह एरे को बिल्कुल नहीं पास कर रहा है, बल्कि इसके तत्वों की एक सूची है, जिसे आरएफ़ंक्शन () नाम से एक एरे में इकट्ठा किया जाता है, लेकिन यह मेरे लिए काम करता है। कुछ समय बाद केन ने अपना समाधान पोस्ट किया, लेकिन मैंने "ऐतिहासिक" संदर्भ के लिए यहां रखा।

calling_function()
{
    variable="a"
    array=( "x", "y", "z" )
    called_function "${variable}" "${array[@]}"
}

called_function()
{
    local_variable="${1}"
    shift
    local_array=("${@}")
}

TheBonsai द्वारा सुधार, धन्यवाद।


19
इस तथ्य के तीन साल बाद, यह जवाब - केवल ऐतिहासिक कारणों से रखा गया - एक दो दिनों के भीतर दो डाउनवोट प्राप्त किए। एसओ पर उदासी से सामान्य रूप से, बिना किसी नोट के क्यों लोग सोचते हैं कि यह वारंट है। ध्यान दें कि यह उत्तर अन्य सभी को पहले से बताता है, और मैंने केन के उत्तर को सर्वश्रेष्ठ समाधान के रूप में स्वीकार किया है। मैं पूरी तरह से जानता हूं कि यह कहीं भी सही नहीं है, लेकिन चार महीने तक यह एसओ पर सबसे अच्छा उपलब्ध था। केन के सही समाधान के लिए दूसरा स्थान हासिल करने के दो साल बाद इसे क्यों खत्म किया जाना चाहिए, यह मुझसे परे है।
DevSolar

@geirha: मैं आपको यह जाँचने के लिए कहूँगा कि प्रश्न किसने पोस्ट किया है, किसने यह उत्तर पोस्ट किया है, और जिसने संभवतः उस उत्तर को स्वीकार कर लिया है जिसे आप "बुरा" कह रहे हैं। ;-) आप प्रश्न में नोट की जांच करना भी चाह सकते हैं , जो बताता है कि यह समाधान केन के लिए नीच क्यों है।
DevSolar

2
मुझे पता है कि आपने प्रश्न पूछा है, आपने यह उत्तर लिखा है, और आपने बुरा उत्तर स्वीकार कर लिया है। इसलिए मैंने इसे इस तरह से शब्द दिया। स्वीकृत उत्तर खराब होने का कारण यह है कि यह संदर्भ द्वारा सरणी को पारित करने की कोशिश कर रहा है, जो कि ऐसी चीज है जिसे आपको वास्तव में बचना चाहिए। इसके अलावा, उदाहरण एक ही स्ट्रिंग में कई तर्कों को मिटा देता है। यदि आपको वास्तव में संदर्भ द्वारा सरणियों को पास करने की आवश्यकता है, तो बैश शुरू करने के लिए गलत भाषा है। यहां तक ​​कि bash 4.3 के नए nameref वेरिएबल्स के साथ, आप सुरक्षित रूप से नाम टकरावों (परिपत्र संदर्भ) से बच नहीं सकते।
जिरह

4
यदि आप प्रत्येक सरणी के तत्वों की संख्या शामिल करते हैं, तो आप कई सरणियाँ पास कर सकते हैं। called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"आदि ... अभी भी कुछ स्पष्ट प्रतिबंधों के साथ, लेकिन वास्तव में, भाषा का समर्थन करने के तरीके से समस्या को हल करने के लिए बेहतर है, बजाय इसके कि आप जिस तरह से अन्य भाषाओं में उपयोग किए जाते हैं, उस तरह से भाषा को काम करने की कोशिश करें।
जिरह

1
@geirha: ठीक है, मुझे लगता है कि हमें सहमत होना पड़ेगा कि हम सहमत नहीं हैं, और आपको मुझे मेरे निर्णय का उत्तर देने वाले न्यायाधीश के रूप में बताना होगा। निजी तौर पर, मैं वैसे भी संदर्भ द्वारा पासिंग ऐरे को प्राथमिकता देता हूं (कोई फर्क नहीं पड़ता कि भाषा, डेटा कॉपी को बचाने के लिए); इससे भी अधिक जब विकल्प पीछे की तरफ झुकना है और अतिरिक्त पैरामीटर के रूप में सरणी आकार पास करना है ...
DevSolar

38

केन बर्टेल्सन समाधान पर टिप्पणी करना और जनवरी हेतिच का जवाब देना:

यह काम किस प्रकार करता है

takes_ary_as_arg descTable[@] optsTable[@]में लाइन try_with_local_arys()समारोह भेजता है:

  1. यह वास्तव में descTableऔर optsTableसरणियों की एक प्रति बनाता है जो takes_ary_as_argफ़ंक्शन के लिए सुलभ हैं ।
  2. takes_ary_as_arg()फ़ंक्शन प्राप्त करता है descTable[@]और optsTable[@]स्ट्रिंग के रूप में, इसका मतलब है कि $1 == descTable[@]और $2 == optsTable[@]
  3. takes_ary_as_arg()फ़ंक्शन की शुरुआत में यह ${!parameter}सिंटैक्स का उपयोग करता है, जिसे अप्रत्यक्ष संदर्भ या कभी-कभी दोहरा संदर्भित कहा जाता है , इसका मतलब है कि हम मान का उपयोग करने के बजाय$1$1 , उदाहरण के विस्तारित मूल्य के मूल्य का उपयोग करते हैं :

    baba=booba
    variable=baba
    echo ${variable} # baba
    echo ${!variable} # booba

    इसी तरह के लिए $2

  4. इसे विस्तार के साथ एक सरणी (निम्नलिखित कोष्ठक ) के रूप में argAry1=("${!1}")बनाता है , सीधे वहां लिखने की तरह । वहाँ की आवश्यकता नहीं है।argAry1=descTable[@]argAry1=("${descTable[@]}")declare

एनबी: यह ध्यान देने योग्य है कि इस ब्रैकेट फॉर्म का उपयोग करके सरणी आरंभीकरण नए सरणी को आंतरिक टैब विभाजकIFS या डिफ़ॉल्ट टैब , न्यूलाइन और स्पेस के अनुसार आरंभ करता है । उस मामले में, क्योंकि यह संकेतन का उपयोग करता था प्रत्येक तत्व स्वयं द्वारा देखा जाता है जैसे कि वह उद्धृत किया गया था (इसके विपरीत[@][*] )।

इसके साथ मेरा आरक्षण

में BASH, स्थानीय चर गुंजाइश वर्तमान समारोह और हर बच्चे को समारोह से कहा जाता है, इस तथ्य यह है कि करने के लिए अनुवाद takes_ary_as_arg()समारोह "देखता है" उन descTable[@]औरoptsTable[@] सरणियों, इस प्रकार यह काम कर रहा है (विवरण के ऊपर देखें)।

यह मामला होने के नाते, सीधे उन चरों को क्यों नहीं देखना चाहिए? यह वहां लिखने जैसा है:

argAry1=("${descTable[@]}")

उपरोक्त विवरण देखें, जो descTable[@]वर्तमान के अनुसार सरणी के मूल्यों को कॉपी करता हैIFS

संक्षेप में

यह गुजर रहा है, संक्षेप में, मूल्य से कुछ भी नहीं - हमेशा की तरह।

मैं डेनिस विलियमसन के ऊपर टिप्पणी करने पर भी जोर देना चाहता हूं: विरल सरणियां (सभी कुंजियों को परिभाषित किए बिना - उनमें "छेद" के साथ) अपेक्षित रूप से काम नहीं करेगा - हम चाबियाँ और "संक्षेप" सरणी को ढीला करेंगे।

कहा जा रहा है, मैं सामान्यीकरण के लिए मूल्य देखता हूं, इस प्रकार फ़ंक्शन बिना नाम जाने बिना ऐरे (या कॉपी) प्राप्त कर सकता है:

  • ~ "प्रतियां" के लिए: यह तकनीक काफी अच्छी है, बस इस बात को ध्यान में रखने की जरूरत है कि सूचकांक (चाबियाँ) चले गए हैं।
  • वास्तविक प्रतियों के लिए: हम कुंजी के लिए एक उदाहरण का उपयोग कर सकते हैं, उदाहरण के लिए:

    eval local keys=(\${!$1})

और फिर एक कॉपी बनाने के लिए उनका उपयोग कर एक लूप। नोट: यहां !इसका उपयोग पिछले अप्रत्यक्ष / दोहरे मूल्यांकन के लिए नहीं किया गया है, बल्कि सरणी संदर्भ में यह सरणी सूचकांकों (कुंजियों) को लौटाता है।

  • और, ज़ाहिर है, अगर हम पास descTableऔर optsTableस्ट्रिंग्स (बिना [@]) थे, तो हम सरणी का उपयोग खुद कर सकते हैं (संदर्भ के अनुसार) eval। एक सामान्य कार्य के लिए जो सरणियों को स्वीकार करता है।

2
केन बर्टेल्सन स्पष्टीकरण के पीछे तंत्र की अच्छी व्याख्या। सवाल "उस मामले में होने के नाते, सीधे उन चरों को खुद क्यों नहीं देखा?", मैं जवाब दूंगा: फ़ंक्शन के पुन: उपयोग के लिए। मान लें कि मुझे किसी फ़ंक्शन को कॉल करने की आवश्यकता है Array1, फिर Array2सरणी नामों को पास करना आसान हो जाता है।
ग्रिफ्रोन

शानदार जवाब, हमें इस तरह की व्याख्या की आवश्यकता है!
atdouard लोपेज

22

यहां मूल समस्या यह है कि डिज़ाइन किए गए / लागू किए गए बैश डेवलपर वास्तव में पुच को खराब कर देते हैं। उन्होंने तय किया कि ${array}यह केवल एक छोटा हाथ ${array[0]}था, जो एक गलत गलती थी। खासकर जब आप उस पर विचार करते हैं${array[0]} कोई अर्थ नहीं है और खाली स्ट्रिंग का मूल्यांकन करता है यदि सरणी प्रकार साहचर्य है।

एक सरणी निरुपित करने से रूप लेता है array=(value1 ... valueN) जहाँ मान का वाक्य-विन्यास होता है [subscript]=string, जिससे किसी विशेष इंडेक्स में सीधे मान को असाइन किया जाता है। इससे यह होता है इसलिए दो प्रकार के सरणियाँ हो सकती हैं, संख्यात्मक रूप से अनुक्रमित और हैश अनुक्रमित (बैश पार्लरों में साहचर्य सरणियाँ)। यह भी बनाता है ताकि आप संख्यात्मक रूप से अनुक्रमित सरणियों को विरल बना सकें। [subscript]=भाग को छोड़ना संख्यात्मक रूप से अनुक्रमित सरणी के लिए छोटा हाथ है, 0 के क्रमिक सूचकांक से शुरू होता है और असाइनमेंट स्टेटमेंट में प्रत्येक नए मूल्य के साथ वृद्धि करता है।

इसलिए, पूरे का${array} मूल्यांकन करना चाहिए सरणी, अनुक्रमित और सभी का । इसे असाइनमेंट स्टेटमेंट के व्युत्क्रम का मूल्यांकन करना चाहिए। किसी भी तीसरे वर्ष सीएस प्रमुख को यह जानना चाहिए। उस स्थिति में, यह कोड ठीक उसी तरह काम करेगा जैसा आप उससे उम्मीद कर सकते हैं:

declare -A foo bar
foo=${bar}

फिर, फ़ंक्शंस के मान से एरेज़ को पास करना और एक ऐरे से दूसरे को असाइन करना बाकी शेल सिंटैक्स के रूप में काम करेगा। लेकिन क्योंकि उन्होंने यह अधिकार नहीं किया था, असाइनमेंट ऑपरेटर= सरणियों के लिए काम नहीं करता है, और सरणियों को कार्यों के मूल्य या सामान्य रूप से ( echo ${array}) कोड के बिना सबमिशन या आउटपुट के लिए पारित नहीं किया जा सकता है ।

तो, अगर यह सही किया गया था, तो निम्न उदाहरण दिखाएगा कि कैसे बाश में सरणियों की उपयोगिता काफी बेहतर हो सकती है:

simple=(first=one second=2 third=3)
echo ${simple}

परिणामी आउटपुट होना चाहिए:

(first=one second=2 third=3)

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

declare -A foo
read foo <file

काश, हम एक अन्यथा शानदार विकास टीम द्वारा नीचे कर दिया गया है।

इस प्रकार, किसी फ़ंक्शन को एरे पास करने के लिए, वास्तव में केवल एक ही विकल्प है, और वह है नेमेरीफ़ फ़ीचर का उपयोग करना:

function funky() {
    local -n ARR

    ARR=$1
    echo "indexes: ${!ARR[@]}"
    echo "values: ${ARR[@]}"
}

declare -A HASH

HASH=([foo]=bar [zoom]=fast)
funky HASH # notice that I'm just passing the word 'HASH' to the function

निम्नलिखित उत्पादन में परिणाम होगा:

indexes: foo zoom
values: bar fast

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

funky "${!array[*]}" "${array[*]}"

और फिर फ़ंक्शन के अंदर कोड का एक गुच्छा सरणी को फिर से इकट्ठा करने के लिए लिख रहा है।


1
उपयोग करने local -nका समाधान स्वीकृत उत्तर की तुलना में बेहतर और अधिक अद्यतित है। यह समाधान किसी भी प्रकार के एक चर के लिए भी काम करेगा। इस उत्तर में सूचीबद्ध उदाहरण को छोटा किया जा सकता है local -n ARR=${1}। हालाँकि / के -nलिए विकल्प केवल बैश संस्करण 4.3 और इसके बाद के संस्करण में उपलब्ध है। localdeclare
ऋचादजसिम्किंस

यह अच्छा है! छोटा गोच: यदि आप अपने फ़ंक्शन के स्थानीय तर्क (जैसे funky ARR) के समान नाम के साथ एक चर पास करते हैं , तो शेल चेतावनी देगा circular name reference, क्योंकि मूल रूप से फ़ंक्शन करने की कोशिश करेगा local -n ARR=ARR। इस विषय पर अच्छी चर्चा
जीन पावलोवस्की

5

DevSolar के उत्तर में एक बिंदु है जो मुझे समझ में नहीं आता है (हो सकता है कि उसके पास ऐसा करने के लिए एक विशिष्ट कारण हो, लेकिन मैं एक के बारे में नहीं सोच सकता): वह तत्व द्वारा तत्व मापदंडों से तत्व सेट करता है, पुनरावृत्त।

एक आसान approuch होगा

called_function()
{
  ...
  # do everything like shown by DevSolar
  ...

  # now get a copy of the positional parameters
  local_array=("$@")
  ...
}

1
ऐसा न करने का मेरा कारण यह है कि मैंने कुछ दिनों पहले तक बैश सरण के साथ खिलौना नहीं बनाया है। पहले मैं पर्ल में बदल जाता था यदि यह जटिल हो जाता था, तो एक विकल्प जो मेरे वर्तमान नौकरी में नहीं है। संकेत के लिए धन्यवाद!
देवसोलर


3

पैरामीटर के रूप में कई सरणियों को पारित करने का एक आसान तरीका चरित्र-पृथक स्ट्रिंग का उपयोग करना है। आप अपनी स्क्रिप्ट को इस तरह कह सकते हैं:

./myScript.sh "value1;value2;value3" "somethingElse" "value4;value5" "anotherOne"

फिर, आप इसे इस तरह अपने कोड में निकाल सकते हैं:

myArray=$1
IFS=';' read -a myArray <<< "$myArray"

myOtherArray=$3
IFS=';' read -a myOtherArray <<< "$myOtherArray"

इस तरह, आप वास्तव में कई सरणियों को पैरामीटर के रूप में पारित कर सकते हैं और यह अंतिम पैरामीटर नहीं है।


1

यह एक रिक्त स्थान के साथ भी काम करता है:

format="\t%2s - %s\n"

function doAction
{
  local_array=("$@")
  for (( i = 0 ; i < ${#local_array[@]} ; i++ ))
    do
      printf "${format}" $i "${local_array[$i]}"
  done
  echo -n "Choose: "
  option=""
  read -n1 option
  echo ${local_array[option]}
  return
}

#the call:
doAction "${tools[@]}"

2
मुझे आश्चर्य है कि यहाँ क्या बात है। यह सिर्फ सामान्य तर्क है। "$ @" सिंटैक्स को रिक्त स्थान के लिए काम करने के लिए बनाया गया है: "$ @" "$ 1" "$ 2" के बराबर है ...
एंड्रियास स्पिंडलर

क्या मैं किसी फ़ंक्शन को 2 सरणियाँ पास कर सकता हूं?
पिहंगाग्नि

1

कुछ तरकीबों के साथ आप वास्तव में नामांकित मापदंडों को फ़ंक्शन के साथ, सरणियों के साथ पास कर सकते हैं।

मैंने जो विधि विकसित की है वह आपको इस तरह से एक फ़ंक्शन को दिए गए मापदंडों तक पहुंचने की अनुमति देता है:

testPassingParams() {

    @var hello
    l=4 @array anArrayWithFourElements
    l=2 @array anotherArrayWithTwo
    @var anotherSingle
    @reference table   # references only work in bash >=4.3
    @params anArrayOfVariedSize

    test "$hello" = "$1" && echo correct
    #
    test "${anArrayWithFourElements[0]}" = "$2" && echo correct
    test "${anArrayWithFourElements[1]}" = "$3" && echo correct
    test "${anArrayWithFourElements[2]}" = "$4" && echo correct
    # etc...
    #
    test "${anotherArrayWithTwo[0]}" = "$6" && echo correct
    test "${anotherArrayWithTwo[1]}" = "$7" && echo correct
    #
    test "$anotherSingle" = "$8" && echo correct
    #
    test "${table[test]}" = "works"
    table[inside]="adding a new value"
    #
    # I'm using * just in this example:
    test "${anArrayOfVariedSize[*]}" = "${*:10}" && echo correct
}

fourElements=( a1 a2 "a3 with spaces" a4 )
twoElements=( b1 b2 )
declare -A assocArray
assocArray[test]="works"

testPassingParams "first" "${fourElements[@]}" "${twoElements[@]}" "single with spaces" assocArray "and more... " "even more..."

test "${assocArray[inside]}" = "adding a new value"

दूसरे शब्दों में, न केवल आप अपने मापदंडों को उनके नाम से बुला सकते हैं (जो कि अधिक पठनीय कोर के लिए बनाता है), आप वास्तव में सरणियों को पारित कर सकते हैं (और चर के संदर्भ में - यह सुविधा केवल बाश 4.3 में हालांकि काम करती है)! इसके अलावा, मैप किए गए चर सभी स्थानीय दायरे में हैं, बस $ 1 (और अन्य) के रूप में।

कोड जो इस काम को बनाता है वह बहुत हल्का है और bash 3 और bash 4 दोनों में काम करता है (ये एकमात्र संस्करण हैं, जिनके साथ मैंने इसका परीक्षण किया है)। यदि आप इस तरह के और ट्रिक्स में रुचि रखते हैं जो बैश को बहुत अच्छे और आसान के साथ विकसित कर रहे हैं, तो आप मेरे बैश इन्फिनिटी फ्रेमवर्क पर एक नज़र डाल सकते हैं , नीचे दिए गए कोड को इस उद्देश्य के लिए विकसित किया गया था।

Function.AssignParamLocally() {
    local commandWithArgs=( $1 )
    local command="${commandWithArgs[0]}"

    shift

    if [[ "$command" == "trap" || "$command" == "l="* || "$command" == "_type="* ]]
    then
        paramNo+=-1
        return 0
    fi

    if [[ "$command" != "local" ]]
    then
        assignNormalCodeStarted=true
    fi

    local varDeclaration="${commandWithArgs[1]}"
    if [[ $varDeclaration == '-n' ]]
    then
        varDeclaration="${commandWithArgs[2]}"
    fi
    local varName="${varDeclaration%%=*}"

    # var value is only important if making an object later on from it
    local varValue="${varDeclaration#*=}"

    if [[ ! -z $assignVarType ]]
    then
        local previousParamNo=$(expr $paramNo - 1)

        if [[ "$assignVarType" == "array" ]]
        then
            # passing array:
            execute="$assignVarName=( \"\${@:$previousParamNo:$assignArrLength}\" )"
            eval "$execute"
            paramNo+=$(expr $assignArrLength - 1)

            unset assignArrLength
        elif [[ "$assignVarType" == "params" ]]
        then
            execute="$assignVarName=( \"\${@:$previousParamNo}\" )"
            eval "$execute"
        elif [[ "$assignVarType" == "reference" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        elif [[ ! -z "${!previousParamNo}" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        fi
    fi

    assignVarType="$__capture_type"
    assignVarName="$varName"
    assignArrLength="$__capture_arrLength"
}

Function.CaptureParams() {
    __capture_type="$_type"
    __capture_arrLength="$l"
}

alias @trapAssign='Function.CaptureParams; trap "declare -i \"paramNo+=1\"; Function.AssignParamLocally \"\$BASH_COMMAND\" \"\$@\"; [[ \$assignNormalCodeStarted = true ]] && trap - DEBUG && unset assignVarType && unset assignVarName && unset assignNormalCodeStarted && unset paramNo" DEBUG; '
alias @param='@trapAssign local'
alias @reference='_type=reference @trapAssign local -n'
alias @var='_type=var @param'
alias @params='_type=params @param'
alias @array='_type=array @param'

1

बस स्वीकृत उत्तर में जोड़ने के लिए, जैसा कि मैंने पाया कि यह अच्छी तरह से काम नहीं करता है अगर सरणी सामग्री कुछ पसंद कर रहे हैं:

RUN_COMMANDS=(
  "command1 param1... paramN"
  "command2 param1... paramN"
)

इस स्थिति में, सरणी का प्रत्येक सदस्य विभाजित हो जाता है, इसलिए फ़ंक्शन द्वारा देखी जाने वाली सरणी इसके बराबर होती है:

RUN_COMMANDS=(
    "command1"
    "param1"
     ...
    "command2"
    ...
)

इस मामले को काम करने के लिए, मैंने पाया कि फ़ंक्शन के लिए चर नाम को पास करना है, फिर eval का उपयोग करें:

function () {
    eval 'COMMANDS=( "${'"$1"'[@]}" )'
    for COMMAND in "${COMMANDS[@]}"; do
        echo $COMMAND
    done
}

function RUN_COMMANDS

बस मेरे 2 ©


1

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

function passarray()
{
    eval array_internally=("$(echo '${'$1'[@]}')")
    # access array now via array_internally
    echo "${array_internally[@]}"
    #...
}

array=(0 1 2 3 4 5)
passarray array # echo's (0 1 2 3 4 5) as expected

मुझे यकीन है कि कोई व्यक्ति विचार के क्लैरियर कार्यान्वयन के साथ आ सकता है, लेकिन मैंने इसे एक सरणी से गुजरने "{array[@]"}और फिर आंतरिक रूप से इसका उपयोग करने से बेहतर समाधान पाया है array_inside=("$@")। यह तब और जटिल हो जाता है जब अन्य स्थिति / getoptsपैरामीटर होते हैं। इन मामलों में, मुझे पहले निर्धारित करना होगा और फिर कुछ संयोजन के उपयोग से सरणी से जुड़े मापदंडों को नहीं हटाना होगाshift एलीमेंट एलिमेंट रिमूवल के हटाना है।

एक शुद्धतावादी दृष्टिकोण इस दृष्टिकोण को भाषा के उल्लंघन के रूप में देखता है, लेकिन व्यावहारिक रूप से बोल रहा है, इस दृष्टिकोण ने मुझे बहुत सारे दु: खों से बचाया है। संबंधित विषय पर, मैं evalएक पैरामीटर के लिए आंतरिक रूप से निर्मित सरणी को असाइन करने के लिए भी उपयोग करता हूं जिसका नाम एक पैरामीटर है जिसे target_varnameमैं फ़ंक्शन को पास करता हूं:

eval $target_varname=$"(${array_inside[@]})"

आशा है कि यह किसी की मदद करता है।


0

आवश्यकता : किसी सरणी में एक स्ट्रिंग खोजने का कार्य।
यह DevSolar के समाधान का एक मामूली सरलीकरण है जिसमें यह उनकी नकल करने के बजाय पारित तर्कों का उपयोग करता है।

myarray=('foobar' 'foxbat')

function isInArray() {
  local item=$1
  shift
  for one in $@; do
    if [ $one = $item ]; then
      return 0   # found
    fi
  done
  return 1       # not found
}

var='foobar'
if isInArray $var ${myarray[@]}; then
  echo "$var found in array"
else
  echo "$var not found in array"
fi 

0

मेरा संक्षिप्त उत्तर है:

function display_two_array {
    local arr1=$1
    local arr2=$2
    for i in $arr1
    do
       "arrary1: $i"
    done
    
    for i in $arr2
    do
       "arrary2: $i"
    done
}

test_array=(1 2 3 4 5)
test_array2=(7 8 9 10 11)

display_two_array "${test_array[*]}" "${test_array2[*]}"
यह ध्यान दिया जाना चाहिए कि ${test_array[*]}और ${test_array2[*]}"" से घिरा होना चाहिए, अन्यथा आप असफल होंगे।


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