फ़ंक्शन तर्क के रूप में सरणी कैसे पास करें?


57

एक सरणी को तर्क के रूप में पारित करने के लिए थोड़ी देर के लिए संघर्ष करना लेकिन यह वैसे भी काम नहीं कर रहा है। मैंने नीचे की तरह कोशिश की है:

#! /bin/bash

function copyFiles{
   arr="$1"
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")

copyFiles $array

स्पष्टीकरण के साथ एक उत्तर अच्छा होगा।

संपादित करें: मूल रूप से, मैं अंततः किसी अन्य स्क्रिप्ट फ़ाइल से फ़ंक्शन को कॉल करूंगा। Plz यदि संभव हो तो बाधाओं की व्याख्या करें।

जवाबों:


84
  • एक सूचकांक के बिना एक सरणी का विस्तार केवल पहला तत्व देता है, उपयोग

    copyFiles "${array[@]}"

    के बजाय

    copyFiles $array
  • वह एक बैंग का उपयोग करें

    #!/bin/bash
  • सही फ़ंक्शन सिंटैक्स का उपयोग करें

    वैध रूपांतर हैं

    function copyFiles {…}
    function copyFiles(){…}
    function copyFiles() {…}
    

    के बजाय

    function copyFiles{…}
  • सरणी पैरामीटर प्राप्त करने के लिए सही सिंटैक्स का उपयोग करें

    arr=("$@")

    के बजाय

    arr="$1"

इसलिये

#!/bin/bash
function copyFiles() {
   arr=("$@")
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")

copyFiles "${array[@]}"

आउटपुट है (मेरी स्क्रिप्ट का नाम है foo)

$ ./foo   
one
two
three

धन्यवाद, लेकिन फ़ंक्शन कॉपी नहीं है {…} एक सही वाक्यविन्यास? हालाँकि मैं एक नया bie हूँ, मैं कुछ प्रोग्राम को सिंटैक्स के साथ सफलतापूर्वक चलाता हूँ।
अहसानुल हक

मान्य वेरिएंट हैं copyFiles {…}और copyFiles(){…}और copyFiles() {…}नहीं, बल्कि copyFiles{…}। बिना वेरिएंट के स्पेस पर ध्यान दें()
AB

19

यदि आप एक या एक से अधिक तर्क और सरणी पास करना चाहते हैं, तो मैं इस परिवर्तन का प्रस्ताव करता हूं @AB
एरे की स्क्रिप्ट में अंतिम तर्क होना चाहिए और केवल एक सरणी को पारित किया जा सकता है

#!/bin/bash
function copyFiles() {
   local msg="$1"   # Save first argument in a variable
   shift            # Shift all arguments to the left (original $1 gets lost)
   local arr=("$@") # Rebuild the array with rest of arguments
   for i in "${arr[@]}";
      do
          echo "$msg $i"
      done
}

array=("one" "two" "three")

copyFiles "Copying" "${array[@]}"

आउटपुट:

$ ./foo   
Copying one
Copying two
Copying three

2
अंत में होने के लिए एक सरणी के बारे में सीखने के लिए +1 और केवल एक ही भेजा जाना चाहिए
डेविड 'गंजा अदरक'

1
shiftउपयोग के लिए धन्यवाद ।
इटाची

कभी-कभी शिफ्ट के तर्क का उपयोग करना भी उपयोगी होता है, इसलिए यदि आपके पास सरणी से पहले 6 तर्क थे, तो आप उपयोग कर सकते हैं shift 6
पालक

आप "बाकी दलीलें" में बदलते हैं arr। क्या बीच में एक सरणी पैरामीटर होना संभव है? या यहां तक ​​कि कई सरणियों पैरामीटर? function copyAndMove() { msg1=$1 ; arr1=...?... ; msg2=? ; arr2=...?... ; msg3=? ; ... }। जैसे मैं इसे अजगर में परिभाषित करूंगा def copyAndMove(msg1="foo", cpFiles=[], msg2="bar", mvFiles=[], msg3="baz"): ...:। कोई बात नहीं, मुझे stackoverflow.com/a/4017175/472245
7

18

आप संदर्भ के रूप में सरणी भी पास कर सकते हैं। अर्थात:

#!/bin/bash

function copyFiles {
   local -n arr=$1

   for i in "${arr[@]}"
   do
      echo "$i"
   done
}

array=("one" "two" "three")

copyFiles array

लेकिन ध्यान दें कि गिरफ्तारी के लिए कोई भी संशोधन सरणी में किया जाएगा।


1
हालांकि, यह बिल्कुल वैसा नहीं था जैसा मैं चाहता हूं, लेकिन यह जानना अभी भी अच्छा है कि कैसे बैश में संदर्भ कार्य से गुजरते हैं। +1 :)
अहसानुल हक

3
बैश 4.3+ की आवश्यकता है
dtmland

8

कुछ समस्याएं हैं। यहाँ काम कर रहा रूप है:

#!/bin/bash
function copyFiles {
   arr=( "$@" )
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • फंक्शन डिक्लेरेशन और के बीच कम से कम स्पेस होने की जरूरत है {

  • आप उपयोग नहीं कर सकते $array, जैसा arrayकि एक सरणी एक चर नहीं है। यदि आप किसी सरणी उपयोग के सभी मान प्राप्त करना चाहते हैं"${array[@]}"

  • में आप मुख्य कार्य घोषणा आप की जरूरत arr="$@"के रूप में "${array[@]}"रिक्तियों से अलग अनुक्रमित मूल्यों के लिए विस्तार होगा, अगर आप का उपयोग $1आप केवल पहले मूल्य मिलेगा। सभी मूल्यों का उपयोग करने के लिए arr="$arr[@]}"


आपको जरूरत हैarr=("$@")
AB

अंतर देखने के लिए, breakनीचे जोड़ें echo "$i"। अपने संस्करण में आप अभी भी सभी तत्वों को देखेंगे। हालांकि, यह तीन लाइनें होनी चाहिए।
एबी

@heemayl: छोटी टाइपो - {दूसरी गोली के आपके सरणी में लापता हो गया ... "$ {array [@]}" ...
Cbhihe

3

यहां थोड़ा बड़ा उदाहरण दिया गया है। स्पष्टीकरण के लिए, कोड में टिप्पणी देखें।

#!/bin/bash -u
# ==============================================================================
# Description
# -----------
# Show the content of an array by displaying each element separated by a
# vertical bar (|).
#
# Arg Description
# --- -----------
# 1   The array
# ==============================================================================
show_array()
{
    declare -a arr=("${@}")
    declare -i len=${#arr[@]}
    # Show passed array
    for ((n = 0; n < len; n++))
    do
        echo -en "|${arr[$n]}"
    done
    echo "|"
}

# ==============================================================================
# Description
# -----------
# This function takes two arrays as arguments together with their sizes and a
# name of an array which should be created and returned from this function.
#
# Arg Description
# --- -----------
# 1   Length of first array
# 2   First array
# 3   Length of second array
# 4   Second array
# 5   Name of returned array
# ==============================================================================
array_demo()
{
    declare -a argv=("${@}")                           # All arguments in one big array
    declare -i len_1=${argv[0]}                        # Length of first array passad
    declare -a arr_1=("${argv[@]:1:$len_1}")           # First array
    declare -i len_2=${argv[(len_1 + 1)]}              # Length of second array passad
    declare -a arr_2=("${argv[@]:(len_1 + 2):$len_2}") # Second array
    declare -i totlen=${#argv[@]}                      # Length of argv array (len_1+len_2+2)
    declare __ret_array_name=${argv[(totlen - 1)]}     # Name of array to be returned

    # Show passed arrays
    echo -en "Array 1: "; show_array "${arr_1[@]}"
    echo -en "Array 2: "; show_array "${arr_2[@]}"

    # Create array to be returned with given name (by concatenating passed arrays in opposite order)
    eval ${__ret_array_name}='("${arr_2[@]}" "${arr_1[@]}")'
}

########################
##### Demo program #####
########################
declare -a array_1=(Only 1 word @ the time)                                       # 6 elements
declare -a array_2=("Space separated words," sometimes using "string paretheses") # 4 elements
declare -a my_out # Will contain output from array_demo()

# A: Length of array_1
# B: First array, not necessary with string parentheses here
# C: Length of array_2
# D: Second array, necessary with string parentheses here
# E: Name of array that should be returned from function.
#          A              B             C              D               E
array_demo ${#array_1[@]} ${array_1[@]} ${#array_2[@]} "${array_2[@]}" my_out

# Show that array_demo really returned specified array in my_out:
echo -en "Returns: "; show_array "${my_out[@]}"

1

सबसे अच्छा तरीका स्थिति तर्क के रूप में पारित करना है। और कुछ नहीं। आप स्ट्रिंग के रूप में पास हो सकते हैं, लेकिन इस तरह से कुछ परेशानी हो सकती है। उदाहरण:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

या

function show_passed_array(){
  while $# -gt 0;do
    echo $1;shift
  done
}

    show_passed_array ${array[@]}

उत्पादन:

  one two three four five

आपका मतलब है कि अगर एरे वैल्यू में स्पेस सिंबल हैं तो आपको तत्वों को क्विट करने के लिए सबसे पहले तत्वों को एक्सेस करना होगा। जहाँ अनुक्रमणिका 0 -> 1, 1 -> 2, ... पहुँच प्राप्त करने के लिए हमेशा $ 1 और Shift के बाद उपयोग करना सबसे अच्छा है। अतिरिक्त कुछ नहीं चाहिए। आप इस तरह किसी भी सरणी के बिना तर्क पारित कर सकते हैं:

show_passed_array one two three four five

बैश मीडिया स्वचालित रूप से पारित तर्कों से एक सरणी बनाता है जो उन्हें कार्य करने के लिए पारित करता है और फिर आपके पास स्थिति तर्क होते हैं। इसके अलावा जब आप $ {array [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[@]})"

यह बदसूरत और अनावश्यक है। यदि आप नाम से सरणी पास करना चाहते हैं, तो इसका array_internallyएक उपनाम बनाएं declare -n array_internally=$1:। और इसके बारे में बाकी "जटिल हो जाता है" और "निर्धारित करें और फिर हटा दें ..." इस बात पर ध्यान दिए बिना लागू होता है कि आप सरणी कैसे पास करते हैं, इसलिए मैं नहीं देखता कि इसका क्या मतलब है। और evalविशेष वर्ण वाले एक सरणी को अंतर्ग्रहण करें, बाद की तारीख में होने वाले दुःख की प्रतीक्षा कर रहा है।
मूरू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.