Comment passer un tableau en argument de fonction?


57

Luttant pendant un moment en passant un tableau en argument mais cela ne fonctionne pas quand même. J'ai essayé comme ci-dessous:

#! /bin/bash

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

}

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

copyFiles $array

Une réponse avec des explications serait bien.

Edit: Fondamentalement, j'appellerai éventuellement la fonction à partir d'un autre fichier de script. Plz expliquer les contraintes si possible.

Réponses:


85
  • Développer un tableau sans index ne donne que le premier élément, utilisez

    copyFiles "${array[@]}"

    au lieu de

    copyFiles $array
  • Utiliser un she-bang

    #!/bin/bash
  • Utilisez la syntaxe de fonction correcte

    Les variantes valides sont

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

    au lieu de

    function copyFiles{…}
  • Utilisez la bonne syntaxe pour obtenir le paramètre de tableau

    arr=("$@")

    au lieu de

    arr="$1"

Donc

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

}

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

copyFiles "${array[@]}"

La sortie est (mon script a le nom foo)

$ ./foo   
one
two
three

merci, mais la fonction copyFiles {…} n’est-elle pas une syntaxe correcte? Bien que je sois un nouveau bie, je lance un programme avec la syntaxe.
Ahsanul Haque

Les variantes valides sont copyFiles {…}and copyFiles(){…}et copyFiles() {…}, mais pas copyFiles{…}. Notez l'espace dans la variante sans()
AB

19

Vous pouvez également passer le tableau comme référence. c'est à dire:

#!/bin/bash

function copyFiles {
   local -n arr=$1

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

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

copyFiles array

mais notez que toutes les modifications apportées à arr seront apportées à array.


2
Quoique, ce n’était pas exactement ce que je voulais, mais c’est quand même bien de savoir comment fonctionnent les tests de référence en bash. +1 :)
Ahsanul Haque

4
Nécessite bash 4.3+
dtmland

19

Si vous souhaitez passer un ou plusieurs arguments ET un tableau, je propose cette modification du script de @AB. Le
tableau doit être le dernier argument et un seul tableau peut être passé.

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

Sortie:

$ ./foo   
Copying one
Copying two
Copying three

2
+1 pour apprendre qu'un groupe doit être à la fin et qu'un seul doit être envoyé
David 'the chad ginger' le

1
Merci pour l' shiftutilisation.
Itachi

Il est également utile d'utiliser parfois l'argument shift, donc si vous aviez 6 arguments avant le tableau, vous pouvez l'utiliser shift 6.
spin

Vous convertissez "le reste des arguments" en arr. Est-il possible d'avoir un paramètre de tableau au milieu? Ou même plusieurs paramètres de tableaux? function copyAndMove() { msg1=$1 ; arr1=...?... ; msg2=? ; arr2=...?... ; msg3=? ; ... }. Comme je définirais en python: def copyAndMove(msg1="foo", cpFiles=[], msg2="bar", mvFiles=[], msg3="baz"): .... Qu'à cela ne tienne, j'ai trouvé stackoverflow.com/a/4017175/472245
towi

8

Il y a quelques problèmes. Voici le formulaire de travail:

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

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • Il doit y avoir au moins un espace entre la déclaration de fonction et {

  • Vous ne pouvez pas utiliser $array, car arrayun tableau n'est pas une variable. Si vous voulez obtenir toutes les valeurs d'un tableau, utilisez"${array[@]}"

  • Dans votre déclaration de fonction principale dont vous avez besoin arr="$@"pour "${array[@]}"développer les valeurs indexées séparées par des espaces, $1vous obtiendrez uniquement la première valeur. Pour obtenir toutes les valeurs, utilisez arr="$arr[@]}".


Vous avez besoinarr=("$@")
AB

Pour voir la différence, ajoutez un breakci - dessous echo "$i". Dans votre version, vous verrez toujours tous les éléments. Cependant, il devrait y avoir trois lignes.
AB

@heemayl: petite faute de frappe - Le {dans votre tableau de la deuxième puce a disparu ... "$ {array [@]}" ...
Cbhihe le

3

Voici un exemple légèrement plus grand. Pour plus d'explications, voir les commentaires dans le 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[@]}"

1

Le meilleur moyen est de passer comme argument de position. Rien d'autre. Vous pouvez passer en tant que chaîne, mais de cette façon peut causer des problèmes. Exemple:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

ou

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

    show_passed_array ${array[@]}

sortie:

  one two three four five

Vous voulez dire que si la valeur du tableau a des symboles d’espace, vous devez d'abord citer les éléments avant de passer pour accéder à la valeur par index dans la fonction use $ 1 $ 2 $ 3 ... paramètres de position. Où index 0 -> 1, 1 -> 2, ... Pour itérer l’accès, il est préférable d’utiliser toujours $ 1 et après Shift. Rien de plus n'est nécessaire. Vous pouvez passer des arguments sans aucun tableau comme celui-ci:

show_passed_array one two three four five

bash media construit automatiquement un tableau à partir des arguments passés qui les ont passés à fonction, puis vous avez des arguments de position. De plus, lorsque vous écrivez $ {array [2]}, vous écrivez réellement les arguments suivants un, deux, trois et vous les transmettez à la fonction. Donc, ces appels sont équivalents.


1

Aussi laid que cela puisse paraître, voici une solution de contournement qui fonctionne tant que vous ne passez pas explicitement un tableau, mais une variable correspondant à un tableau:

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

Je suis sûr que quelqu'un peut proposer une mise en œuvre plus claire de l'idée, mais j'ai trouvé que c'était une meilleure solution que de passer un tableau au fur "{array[@]"}et à mesure , puis d'y accéder en interne à l'aide de array_inside=("$@"). Cela devient compliqué quand il y a d'autres getoptsparamètres de position . Dans ces cas, j'ai d'abord dû déterminer, puis supprimer les paramètres non associés au tableau en utilisant une combinaison de la shiftsuppression d'éléments de tableau.

Une perspective puriste considère probablement cette approche comme une violation de la langue, mais, d'une manière pragmatique, cette approche m'a évité beaucoup de chagrin. Sur un sujet connexe, j'utilise également evalpour affecter un tableau construit en interne à une variable nommée en fonction d'un paramètre que target_varnameje transmets à la fonction:

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

C'est moche et inutile. Si vous voulez passer le tableau par nom, faire array_internallyun alias de celui - ci: declare -n array_internally=$1. Et le reste, à propos de "devient compliqué" et de "déterminer puis supprimer ..." s'applique quelle que soit la façon dont vous passez le tableau, je ne vois donc pas à quoi ça sert. Et evalutiliser un tableau contenant potentiellement des caractères spéciaux n’attend que le chagrin à une date ultérieure.
Muru
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.