Wie übergebe ich ein Array als Funktionsargument?

57

Mühe dich eine Weile, ein Array als Argument zu übergeben, aber es funktioniert trotzdem nicht. Ich habe wie folgt versucht:

#! /bin/bash

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

}

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

copyFiles $array

Eine Antwort mit Erklärung wäre nett.

Bearbeiten: Grundsätzlich werde ich die Funktion irgendwann aus einer anderen Skriptdatei aufrufen. Bitte erläutern Sie die Einschränkungen, wenn möglich.

Ahsanul Haque
quelle

Antworten:

85
  • Wenn Sie ein Array ohne Index erweitern, erhalten Sie nur das erste Element, use

    copyFiles "${array[@]}"

    Anstatt von

    copyFiles $array
  • Benutze eine Pauke

    #!/bin/bash
  • Verwenden Sie die richtige Funktionssyntax

    Gültige Varianten sind

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

    Anstatt von

    function copyFiles{…}
  • Verwenden Sie die richtige Syntax, um den Array-Parameter abzurufen

    arr=("$@")

    Anstatt von

    arr="$1"

Deshalb

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

}

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

copyFiles "${array[@]}"

Ausgabe ist (mein Skript hat den Namen foo)

$ ./foo   
one
two
three
AB
quelle
Danke, aber ist die Funktion copyFiles {…} nicht eine korrekte Syntax? Obwohl ich ein neues Mädchen bin, führe ich ein Programm erfolgreich mit der Syntax aus.
Ahsanul Haque
Gültige Varianten sind copyFiles {…}und copyFiles(){…}und copyFiles() {…}, aber nicht copyFiles{…}. Beachten Sie das Leerzeichen in der Variante ohne()
AB
19

Sie können das Array auch als Referenz übergeben. dh:

#!/bin/bash

function copyFiles {
   local -n arr=$1

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

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

copyFiles array

Beachten Sie jedoch, dass alle Änderungen an arr an array vorgenommen werden.


quelle
2
Es war zwar nicht genau das, was ich will, aber es ist immer noch schön zu wissen, wie man durch Nachschlagewerke in Bash geht. +1 :)
Ahsanul Haque
4
Benötigt bash 4.3+
dtmland
19

Wenn Sie ein oder mehrere Argumente UND ein Array übergeben möchten, schlage ich vor, dass diese Änderung am Skript von @AB
Array das letzte Argument sein sollte und nur ein Array übergeben werden kann

#!/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[@]}"

Ausgabe:

$ ./foo   
Copying one
Copying two
Copying three
SBF
quelle
2
+1 für das Lernen, dass ein Array am Ende sein muss und nur eines gesendet werden sollte
David 'der kahle Ingwer'
1
Vielen Dank für die shiftNutzung.
Itachi
Manchmal ist es auch nützlich, das Argument von shift zu verwenden. Wenn Sie also 6 Argumente vor dem Array hatten, können Sie es verwenden shift 6.
Spinup
Sie konvertieren "den Rest der Argumente" in arr. Ist es möglich, einen Array-Parameter in der Mitte zu haben? Oder sogar mehrere Array-Parameter? function copyAndMove() { msg1=$1 ; arr1=...?... ; msg2=? ; arr2=...?... ; msg3=? ; ... }. Wie würde ich es in Python definieren: def copyAndMove(msg1="foo", cpFiles=[], msg2="bar", mvFiles=[], msg3="baz"): .... Egal
am
8

Es gibt einige Probleme. Hier ist die Arbeitsform:

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

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • Zwischen Funktionsdeklaration und muss mindestens ein Leerzeichen stehen {

  • Sie können nicht verwenden $array, da arrayes sich bei einem Array nicht um eine Variable handelt. Wenn Sie alle Werte eines Arrays erhalten möchten, verwenden Sie"${array[@]}"

  • In Ihrer Hauptfunktionsdeklaration müssen Sie arr="$@"als "${array[@]}"Erweiterung die durch Leerzeichen getrennten indizierten Werte verwenden, wenn Sie verwenden $1, würden Sie nur den ersten Wert erhalten. Um alle Werte zu erhalten, verwenden Sie arr="$arr[@]}".

heemayl
quelle
Sie brauchenarr=("$@")
AB
Um den Unterschied zu sehen, fügen Sie breakunten ein echo "$i". In Ihrer Version sehen Sie weiterhin alle Elemente. Es sollten jedoch drei Zeilen sein.
AB
@heemayl: kleiner Tippfehler - Das {in Ihrem Array der zweiten Kugel ist verschwunden ... "$ {array [@]}" ...
Cbhihe
3

Hier folgt ein etwas größeres Beispiel. Erläuterungen finden Sie in den Kommentaren im Code.

#!/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[@]}"
Ulf Oreborn
quelle
1

Der beste Weg ist, als Positionsargumente zu übergeben. Nichts anderes. Sie können als Zeichenfolge übergeben, dies kann jedoch zu Problemen führen. Beispiel:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

oder

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

    show_passed_array ${array[@]}

Ausgabe:

  one two three four five

Sie meinen, wenn der Array-Wert Leerzeichen enthält, müssen Sie die Elemente zuerst in Anführungszeichen setzen, bevor Sie auf den Wert durch den Index in der Funktion zugreifen. Verwenden Sie dazu die Positionsparameter $ 1 $ 2 $ 3 .... Wobei Index 0 -> 1, 1 -> 2, ... Um den Zugriff zu iterieren, ist es am besten, immer $ 1 und nach der Umschalttaste zu verwenden. Es wird nichts zusätzliches benötigt. Sie können Argumente ohne ein Array wie dieses übergeben:

show_passed_array one two three four five

bash media erstellt automatisch ein Array aus übergebenen Argumenten, die an function übergeben wurden, und Sie haben dann Positionsargumente. Wenn Sie außerdem $ {array [2]} schreiben, schreiben Sie wirklich das folgende Argument eins, zwei, drei, vier und übergeben es an die Funktion. Diese Anrufe sind also gleichwertig.

Anatoly
quelle
1

So hässlich es auch ist, hier ist eine Problemumgehung, die funktioniert, solange Sie nicht explizit ein Array übergeben, sondern eine Variable, die einem Array entspricht:

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

Ich bin sicher, dass jemand eine sauberere Implementierung der Idee finden kann, aber ich habe festgestellt, dass dies eine bessere Lösung ist, als ein Array als zu übergeben "{array[@]"}und dann intern darauf zuzugreifen array_inside=("$@"). Dies wird kompliziert, wenn andere Positions- / getoptsParameter vorhanden sind. In diesen Fällen musste ich zuerst die Parameter ermitteln und dann entfernen, die nicht mit dem Array verknüpft waren, indem ich eine Kombination aus shiftund Entfernung von Array-Elementen verwendete.

Eine puristische Perspektive betrachtet diesen Ansatz wahrscheinlich als eine Verletzung der Sprache, aber pragmatisch gesehen hat dieser Ansatz mir viel Kummer erspart. Zu einem verwandten Thema verwende ich auch eval, um einer Variablen mit dem Namen eines Parameters, den target_varnameich an die Funktion übergebe , ein intern erstelltes Array zuzuweisen :

eval $target_varname=$"(${array_inside[@]})"
Blake Schultze
quelle
Das ist hässlich und unnötig. Wenn Sie das Array mit Namen übergeben möchten, machen Sie array_internallyeinen Alias davon: declare -n array_internally=$1. Und der Rest davon über "wird kompliziert" und "bestimmen und dann entfernen ..." gilt unabhängig davon, wie Sie das Array übergeben, also verstehe ich nicht, was der Sinn davon ist. Und evalein Array, das möglicherweise Sonderzeichen enthält, wartet nur darauf, dass es zu einem späteren Zeitpunkt zu Trauer kommt.
muru