web-dev-qa-db-fra.com

Comment retourner un tableau en bash sans utiliser de globals?

J'ai une fonction qui crée un tableau et je veux renvoyer le tableau à l'appelant:

create_array() {
  local my_list=("a", "b", "c")
  echo "${my_list[@]}"
}

my_algorithm() {
  local result=$(create_array)
}

Avec cela, je ne reçois qu'une chaîne étendue. Comment puis-je "retourner" ma liste sans utiliser quoi que ce soit de global?

67
helpermethod

Quel est le problème avec globals?

Retourner des tableaux n'est vraiment pas pratique. Il y a beaucoup de pièges.

Cela dit, voici une technique qui fonctionne si la variable a le même nom si elle est OK:

$ f () { local a; a=(abc 'def ghi' jkl); declare -p a; }
$ g () { local a; eval $(f); declare -p a; }
$ f; declare -p a; echo; g; declare -p a
declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found

declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found

Les commandes declare -p (À l'exception de celle de f() permettent d'afficher l'état du tableau à des fins de démonstration. Dans f(), il est utilisé comme mécanisme pour renvoyer le tableau. tableau.

Si vous avez besoin que le tableau ait un nom différent, vous pouvez faire quelque chose comme ceci:

$ g () { local b r; r=$(f); r="declare -a b=${r#*=}"; eval "$r"; declare -p a; declare -p b; }
$ f; declare -p a; echo; g; declare -p a
declare -a a='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found

-bash: declare: a: not found
declare -a b='([0]="abc" [1]="def ghi" [2]="jkl")'
-bash: declare: a: not found
34

Avec la version 4.3 et les versions ultérieures de Bash, vous pouvez utiliser un nameref pour que l'appelant puisse passer le nom du tableau et l'appelé puisse utiliser un nameref pour remplir le tableau nommé, indirectement.

#!/usr/bin/env bash

create_array() {
    local -n arr=$1              # use nameref for indirection
    arr=(one "two three" four)
}

use_array() {
    local my_array
    create_array my_array       # call function to populate the array
    echo "inside use_array"
    declare -p my_array         # test the array
}

use_array                       # call the main function

Produit la sortie:

inside use_array
declare -a my_array=([0]="one" [1]="two three" [2]="four")

Vous pouvez également faire en sorte que la fonction mette à jour un tableau existant:

update_array() {
    local -n arr=$1              # use nameref for indirection
    arr+=("two three" four)      # update the array
}

use_array() {
    local my_array=(one)
    update_array my_array       # call function to update the array
}

C'est une approche plus élégante et efficace car nous n'avons pas besoin de substitution de commande $() pour saisir la sortie standard de la fonction en cours appelé. Il est également utile que la fonction retourne plusieurs sorties. Nous pouvons simplement utiliser autant de namerefs que le nombre de sorties.


Voici ce que Bash Manual à propos de nameref:

L'attribut nameref peut être affecté à une variable à l'aide de l'option -n des commandes intégrées declare ou locales (voir Intégrations Bash) pour créer un nom ou une référence à une autre variable. Ceci permet aux variables d'être manipulées indirectement. Chaque fois que la variable nameref est référencée, affectée, non définie ou que ses attributs sont modifiés (autre que l’utilisation ou la modification de l’attribut nameref lui-même), l’opération est effectivement effectuée sur la variable spécifiée par la valeur de la variable nameref. Un nameref est couramment utilisé dans les fonctions du shell pour faire référence à une variable dont le nom est transmis en tant qu'argument à la fonction. Par exemple, si un nom de variable est passé à une fonction Shell en tant que premier argument,

declare -n ref = $ 1 dans la fonction crée une variable de nommage ref dont la valeur est le nom de la variable transmis en tant que premier argument. Les références et les affectations à ref, ainsi que les modifications apportées à ses attributs, sont traitées comme des références, des affectations et des modifications d'attribut à la variable dont le nom a été passé en tant que $ 1.

22
codeforester

Bash ne peut pas transmettre les structures de données en tant que valeurs de retour. Une valeur de retour doit être un état de sortie numérique compris entre 0 et 255. Cependant, vous pouvez certainement utiliser la substitution de commande ou de processus pour passer des commandes à une instruction eval si vous êtes tellement enclin.

Cela vaut rarement la peine, IMHO. Si vous devez transmettre des structures de données dans Bash, utilisez une variable globale - c'est ce à quoi elles servent. Cependant, si vous ne voulez pas faire cela pour une raison quelconque, pensez en termes de paramètres de position.

Votre exemple pourrait facilement être réécrit pour utiliser des paramètres de position au lieu de variables globales:

use_array () {
    for idx in "$@"; do
        echo "$idx"
    done
}

create_array () {
    local array=("a" "b" "c")
    use_array "${array[@]}"
}

Tout cela crée cependant une certaine complexité inutile. Les fonctions Bash fonctionnent généralement mieux lorsque vous les traitez davantage comme des procédures avec des effets secondaires et que vous les appelez en séquence.

# Gather values and store them in FOO.
get_values_for_array () { :; }

# Do something with the values in FOO.
process_global_array_variable () { :; }

# Call your functions.
get_values_for_array
process_global_array_variable

Si tout ce qui vous préoccupe est de polluer votre espace de noms global, vous pouvez également utiliser le nset builtin pour supprimer une variable globale une fois que vous avez terminé. En vous servant de votre exemple d’origine, laissez ma_sélection être global (en supprimant le mot-clé local) et ajoutez unset my_list à la fin de mon_algorithme à nettoyer après vous-même.

15
Todd A. Jacobs

Utilisez la technique développée par Matt McClure: http://notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html

Éviter les variables globales signifie que vous pouvez utiliser la fonction dans un canal. Voici un exemple:

#!/bin/bash

makeJunk()
{
   echo 'this is junk'
   echo '#more junk and "b@d" characters!'
   echo '!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'"'"
}

processJunk()
{
    local -a arr=()    
    # read each input and add it to arr
    while read -r line
    do 
       arr[${#arr[@]}]='"'"$line"'" is junk'; 
    done;

    # output the array as a string in the "declare" representation
    declare -p arr | sed -e 's/^declare -a [^=]*=//'
}

# processJunk returns the array in a flattened string ready for "declare"
# Note that because of the pipe processJunk cannot return anything using
# a global variable
returned_string=`makeJunk | processJunk`

# convert the returned string to an array named returned_array
# declare correctly manages spaces and bad characters
eval "declare -a returned_array=${returned_string}"

for junk in "${returned_array[@]}"
do
   echo "$junk"
done

La sortie est:

"this is junk" is junk
"#more junk and "b@d" characters!" is junk
"!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'" is junk
10
Steve Zobell

Vous n'étiez pas si loin avec votre solution d'origine. Vous avez eu quelques problèmes, vous avez utilisé une virgule comme séparateur et vous n'avez pas réussi à capturer les éléments retournés dans une liste. Essayez ceci:

my_algorithm() {
  local result=( $(create_array) )
}

create_array() {
  local my_list=("a" "b" "c")  
  echo "${my_list[@]}" 
}

Considérant les commentaires sur les espaces incorporés, quelques ajustements utilisant IFS peuvent résoudre ceci:

my_algorithm() {
  oldIFS="$IFS"
  IFS=','
  local result=( $(create_array) )
  IFS="$oldIFS"
  echo "Should be 'c d': ${result[1]}"
}

create_array() {
  IFS=','
  local my_list=("a b" "c d" "e f") 
  echo "${my_list[*]}" 
}
9
cdarke

Une solution pure bash, minimale et robuste basée sur la commande 'declare -p' - sans variables globales insensées

Cette approche implique les trois étapes suivantes:

  1. Convertissez le tableau avec 'declare -p' et enregistrez la sortie dans une variable.
    myVar="$( declare -p myArray )"
    La sortie de l'instruction declare -p Peut être utilisée pour recréer le tableau. Par exemple, la sortie de declare -p myVar Pourrait ressembler à ceci:
    declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
  2. Utilisez l'écho intégré pour transmettre la variable à une fonction ou pour la renvoyer à partir de là.
    • Afin de préserver les espaces dans les champs de tableau lors de l'écho de la variable, IFS est défini temporairement sur un caractère de contrôle (par exemple, une tabulation verticale).
    • Seul le côté droit de l'instruction declare dans la variable doit être répercuté - ceci peut être obtenu en développant le paramètre de la forme $ {paramètre # Mot}. Comme pour l'exemple ci-dessus: ${myVar#*=}
  3. Enfin, recréez le tableau où il est passé en utilisant les commandes intégrées eval et 'declare -a'.

Exemple 1 - retourne un tableau d'une fonction

#!/bin/bash

# Example 1 - return an array from a function

function my-fun () {
 # set up a new array with 3 fields - note the whitespaces in the
 # 2nd (2 spaces) and 3rd (2 tabs) field
 local myFunArray=( "1st field" "2nd  field" "3rd       field" )

 # show its contents on stderr (must not be output to stdout!)
 echo "now in $FUNCNAME () - showing contents of myFunArray" >&2
 echo "by the help of the 'declare -p' builtin:" >&2
 declare -p myFunArray >&2

 # return the array
 local myVar="$( declare -p myFunArray )"
 local IFS=$'\v';
 echo "${myVar#*=}"

 # if the function would continue at this point, then IFS should be
 # restored to its default value: <space><tab><newline>
 IFS=' '$'\t'$'\n';
}

# main

# call the function and recreate the array that was originally
# set up in the function
eval declare -a myMainArray="$( my-fun )"

# show the array contents
echo ""
echo "now in main part of the script - showing contents of myMainArray"
echo "by the help of the 'declare -p' builtin:"
declare -p myMainArray

# end-of-file

Résultat de l'exemple 1:

now in my-fun () - showing contents of myFunArray
by the help of the 'declare -p' builtin:
declare -a myFunArray='([0]="1st field" [1]="2nd  field" [2]="3rd       field")'

now in main part of the script - showing contents of myMainArray
by the help of the 'declare -p' builtin:
declare -a myMainArray='([0]="1st field" [1]="2nd  field" [2]="3rd      field")'

Exemple 2 - passer un tableau à une fonction

#!/bin/bash

# Example 2 - pass an array to a function

function my-fun () {
 # recreate the array that was originally set up in the main part of
 # the script
 eval declare -a myFunArray="$( echo "$1" )"

 # note that myFunArray is local - from the bash(1) man page: when used
 # in a function, declare makes each name local, as with the local
 # command, unless the ‘-g’ option is used.

 # IFS has been changed in the main part of this script - now that we
 # have recreated the array it's better to restore it to the its (local)
 # default value: <space><tab><newline>
 local IFS=' '$'\t'$'\n';

 # show contents of the array
 echo ""
 echo "now in $FUNCNAME () - showing contents of myFunArray"
 echo "by the help of the 'declare -p' builtin:"
 declare -p myFunArray
}

# main

# set up a new array with 3 fields - note the whitespaces in the
# 2nd (2 spaces) and 3rd (2 tabs) field
myMainArray=( "1st field" "2nd  field" "3rd     field" )

# show the array contents
echo "now in the main part of the script - showing contents of myMainArray"
echo "by the help of the 'declare -p' builtin:"
declare -p myMainArray

# call the function and pass the array to it
myVar="$( declare -p myMainArray )"
IFS=$'\v';
my-fun $( echo "${myVar#*=}" )

# if the script would continue at this point, then IFS should be restored
# to its default value: <space><tab><newline>
IFS=' '$'\t'$'\n';

# end-of-file

Résultat de l'exemple 2:

now in the main part of the script - showing contents of myMainArray
by the help of the 'declare -p' builtin:
declare -a myMainArray='([0]="1st field" [1]="2nd  field" [2]="3rd      field")'

now in my-fun () - showing contents of myFunArray
by the help of the 'declare -p' builtin:
declare -a myFunArray='([0]="1st field" [1]="2nd  field" [2]="3rd       field")'
8
F.M.

Exemple utile: retourner un tableau de fonction

function Query() {
  local _tmp=`echo -n "$*" | mysql 2>> zz.err`;
  echo -e "$_tmp";
}

function StrToArray() {
  IFS=$'\t'; set $1; for item; do echo $item; done; IFS=$oIFS;
}

sql="SELECT codi, bloc, requisit FROM requisits ORDER BY codi";
qry=$(Query $sql0);
IFS=$'\n';
for row in $qry; do
  r=( $(StrToArray $row) );
  echo ${r[0]} - ${r[1]} - ${r[2]};
done
4
Rafael

[ Remarque: Ce qui suit a été rejeté comme modification de cette réponse pour raisons qui n'ont aucun sens pour moi. (puisque l'édition était et non destinée à l'auteur ()), je prends donc la suggestion d'en faire une publication séparée répondre.]

Une implémentation plus simple de adaptation par Steve Zobell de la technique de Matt McClure utilise le bash intégré (depuis version == 4 ) readarraycomme suggéré RastaMatt pour créer une représentation d’un tableau pouvant être converti en tableau au moment de l’exécution. (Notez que readarray et mapfile nomment le même code.) Il évite toujours les globales (autorisant l'utilisation de la fonction dans un tube) et gère toujours les caractères désagréables.

Pour des exemples plus développés (par exemple, plus de modularisation) mais toujours un peu comme des jouets, voir bash_pass_arrays_between_functions . Vous trouverez ci-dessous quelques exemples faciles à exécuter, fournis ici pour éviter aux modérateurs de parler de liens externes.

Coupez le bloc suivant et collez-le dans un terminal bash pour créer /tmp/source.sh et /tmp/junk1.sh:

FP='/tmp/source.sh'     # path to file to be created for `source`ing
cat << 'EOF' > "${FP}"  # suppress interpretation of variables in heredoc
function make_junk {
   echo 'this is junk'
   echo '#more junk and "b@d" characters!'
   echo '!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'"'"
}

### Use 'readarray' (aka 'mapfile', bash built-in) to read lines into an array.
### Handles blank lines, whitespace and even nastier characters.
function lines_to_array_representation {
    local -a arr=()
    readarray -t arr
    # output array as string using 'declare's representation (minus header)
    declare -p arr | sed -e 's/^declare -a [^=]*=//'
}
EOF

FP1='/tmp/junk1.sh'      # path to script to run
cat << 'EOF' > "${FP1}"  # suppress interpretation of variables in heredoc
#!/usr/bin/env bash

source '/tmp/source.sh'  # to reuse its functions

returned_string="$(make_junk | lines_to_array_representation)"
eval "declare -a returned_array=${returned_string}"
for elem in "${returned_array[@]}" ; do
    echo "${elem}"
done
EOF
chmod u+x "${FP1}"
# newline here ... just hit Enter ...

Courir /tmp/junk1.sh: la sortie devrait être

this is junk
#more junk and "b@d" characters!
!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'

Remarque lines_to_array_representation gère également les lignes vides. Essayez de coller le bloc suivant dans votre terminal bash:

FP2='/tmp/junk2.sh'      # path to script to run
cat << 'EOF' > "${FP2}"  # suppress interpretation of variables in heredoc
#!/usr/bin/env bash

source '/tmp/source.sh'  # to reuse its functions

echo '`bash --version` the normal way:'
echo '--------------------------------'
bash --version
echo # newline

echo '`bash --version` via `lines_to_array_representation`:'
echo '-----------------------------------------------------'
bash_version="$(bash --version | lines_to_array_representation)"
eval "declare -a returned_array=${bash_version}"
for elem in "${returned_array[@]}" ; do
    echo "${elem}"
done
echo # newline

echo 'But are they *really* the same? Ask `diff`:'
echo '-------------------------------------------'

echo 'You already know how to capture normal output (from `bash --version`):'
declare -r PATH_TO_NORMAL_OUTPUT="$(mktemp)"
bash --version > "${PATH_TO_NORMAL_OUTPUT}"
echo "normal output captured to file @ ${PATH_TO_NORMAL_OUTPUT}"
ls -al "${PATH_TO_NORMAL_OUTPUT}"
echo # newline

echo 'Capturing L2AR takes a bit more work, but is not onerous.'
echo "Look @ contents of the file you're about to run to see how it's done."

declare -r RAW_L2AR_OUTPUT="$(bash --version | lines_to_array_representation)"
declare -r PATH_TO_COOKED_L2AR_OUTPUT="$(mktemp)"
eval "declare -a returned_array=${RAW_L2AR_OUTPUT}"
for elem in "${returned_array[@]}" ; do
    echo "${elem}" >> "${PATH_TO_COOKED_L2AR_OUTPUT}"
done
echo "output from lines_to_array_representation captured to file @ ${PATH_TO_COOKED_L2AR_OUTPUT}"
ls -al "${PATH_TO_COOKED_L2AR_OUTPUT}"
echo # newline

echo 'So are they really the same? Per'
echo "\`diff -uwB "${PATH_TO_NORMAL_OUTPUT}" "${PATH_TO_COOKED_L2AR_OUTPUT}" | wc -l\`"
diff -uwB "${PATH_TO_NORMAL_OUTPUT}" "${PATH_TO_COOKED_L2AR_OUTPUT}" | wc -l
echo '... they are the same!'
EOF
chmod u+x "${FP2}"
# newline here ... just hit Enter ...

Courir /tmp/junk2.sh @ ligne de commande. Votre sortie devrait être semblable à la mienne:

`bash --version` the normal way:
--------------------------------
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

`bash --version` via `lines_to_array_representation`:
-----------------------------------------------------
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

But are they *really* the same? Ask `diff`:
-------------------------------------------
You already know how to capture normal output (from `bash --version`):
normal output captured to file @ /tmp/tmp.Ni1bgyPPEw
-rw------- 1 me me 308 Jun 18 16:27 /tmp/tmp.Ni1bgyPPEw

Capturing L2AR takes a bit more work, but is not onerous.
Look @ contents of the file you're about to run to see how it's done.
output from lines_to_array_representation captured to file @ /tmp/tmp.1D6O2vckGz
-rw------- 1 me me 308 Jun 18 16:27 /tmp/tmp.1D6O2vckGz

So are they really the same? Per
`diff -uwB /tmp/tmp.Ni1bgyPPEw /tmp/tmp.1D6O2vckGz | wc -l`
0
... they are the same!
3
TomRoche

Voici une solution sans références de tableau externes ni manipulation IFS:

# add one level of single quotes to args, eval to remove
squote () {
    local a=("$@")
    a=("${a[@]//\'/\'\\\'\'}")   # "'" => "'\''"
    a=("${a[@]/#/\'}")           # add "'" prefix to each Word
    a=("${a[@]/%/\'}")           # add "'" suffix to each Word
    echo "${a[@]}"
}

create_array () {
    local my_list=(a "b 'c'" "\\\"d
")
    squote "${my_list[@]}"
}

my_algorithm () {
    eval "local result=($(create_array))"
    # result=([0]="a" [1]="b 'c'" [2]=$'\\"d\n')
}
2
Matei David

J'ai récemment découvert un problème dans BASH en ce sens qu'une fonction a un accès direct aux variables déclarées dans les fonctions situées plus haut dans la pile d'appels. Je viens tout juste de commencer à réfléchir à la façon d'exploiter cette fonctionnalité (elle promet à la fois des avantages et des dangers), mais une application évidente est une solution à l'esprit de ce problème.

Je préférerais également obtenir une valeur de retour plutôt que d'utiliser une variable globale lors de la délégation de la création d'un tableau. Ma préférence a plusieurs raisons, parmi lesquelles il faut éviter de perturber une valeur préexistante et d'éviter de laisser une valeur qui pourrait être invalide lors d'un accès ultérieur. Bien qu'il existe des solutions de contournement à ces problèmes, le plus simple est de laisser la variable hors de portée lorsque le code est terminé.

Ma solution garantit que le tableau est disponible lorsque cela est nécessaire et est ignoré lorsque la fonction est renvoyée, et laisse non perturbée une variable globale du même nom.

#!/bin/bash

myarr=(global array elements)

get_an_array()
{
   myarr=( $( date +"%Y %m %d" ) )
}

request_array()
{
   declare -a myarr
   get_an_array "myarr"
   echo "New contents of local variable myarr:"
   printf "%s\n" "${myarr[@]}"
}

echo "Original contents of global variable myarr:"
printf "%s\n" "${myarr[@]}"
echo

request_array 

echo
echo "Confirm the global myarr was not touched:"
printf "%s\n" "${myarr[@]}"

Voici la sortie de ce code: program output

Lorsque function request_array appelle get_an_array , get_an_array peut définir directement la variable myarr qui est locale à request_array . Puisque myarr est créé avec declare, il est local à request_array et sort donc de la portée lorsque request_array est renvoyé.

Bien que cette solution ne renvoie pas littéralement une valeur, je suggère que, dans son ensemble, elle satisfasse les promesses d'une valeur de retour de fonction vraie.

2
chuckj

J'ai essayé diverses implémentations, et aucun tableau préservé contenant des éléments avec des espaces ... car ils devaient tous utiliser echo.

# These implementations only work if no array items contain spaces.
use_array() {  eval echo  '(' \"\${${1}\[\@\]}\" ')';  }
use_array() {  local _array="${1}[@]"; echo '(' "${!_array}" ')';  }

Solution

Puis je suis tombé sur réponse de Dennis Williamson . J'ai incorporé sa méthode dans les fonctions suivantes afin qu'elles puissent a) accepter un tableau arbitraire et b) être utilisées pour passer, dupliquer et ajouter des tableaux.

# Print array definition to use with assignments, for loops, etc.
#   varname: the name of an array variable.
use_array() {
    local r=$( declare -p $1 )
    r=${r#declare\ -a\ *=}
    # Strip keys so printed definition will be a simple list (like when using
    # "${array[@]}").  One side effect of having keys in the definition is 
    # that when appending arrays (i.e. `a1+=$( use_array a2 )`), values at
    # matching indices merge instead of pushing all items onto array.
    echo ${r//\[[0-9]\]=}
}
# Same as use_array() but preserves keys.
use_array_assoc() {
    local r=$( declare -p $1 )
    echo ${r#declare\ -a\ *=}
}  

Ensuite, d'autres fonctions peuvent renvoyer un tableau à l'aide d'une sortie capturable ou d'arguments indirects.

# catchable output
return_array_by_printing() {
    local returnme=( "one" "two" "two and a half" )
    use_array returnme
}
eval test1=$( return_array_by_printing )

# indirect argument
return_array_to_referenced_variable() {
    local returnme=( "one" "two" "two and a half" )
    eval $1=$( use_array returnme )
}
return_array_to_referenced_variable test2

# Now both test1 and test2 are arrays with three elements
2
Stephen M. Harris

J'avais besoin d'une fonctionnalité similaire récemment, alors voici un mélange des suggestions de RashaMatt et Steve Zobell .

  1. echo chaque élément de tableau/liste en tant que ligne séparée depuis une fonction
  2. utilisez mapfile pour lire tous les éléments de tableau/liste en écho avec une fonction.

Autant que je sache, les chaînes sont préservées et les espaces sont préservés.

#!bin/bash

function create-array() {
  local somearray=("aaa" "bbb ccc" "d" "e f g h")
  for elem in "${somearray[@]}"
  do
    echo "${elem}"
  done
}

mapfile -t resa <<< "$(create-array)"

# quick output check
declare -p resa

Quelques autres variations…

#!/bin/bash

function create-array-from-ls() {
  local somearray=("$(ls -1)")
  for elem in "${somearray[@]}"
  do
    echo "${elem}"
  done
}

function create-array-from-args() {
  local somearray=("$@")
  for elem in "${somearray[@]}"
  do
    echo "${elem}"
  done
}


mapfile -t resb <<< "$(create-array-from-ls)"
mapfile -t resc <<< "$(create-array-from-args 'xxx' 'yy zz' 't s u' )"

sentenceA="create array from this sentence"
sentenceB="keep this sentence"

mapfile -t resd <<< "$(create-array-from-args ${sentenceA} )"
mapfile -t rese <<< "$(create-array-from-args "$sentenceB" )"
mapfile -t resf <<< "$(create-array-from-args "$sentenceB" "and" "this words" )"

# quick output check
declare -p resb
declare -p resc
declare -p resd
declare -p rese
declare -p resf
2
compota

Cela peut aussi être fait simplement en passant une variable de tableau à la fonction et en assignant des valeurs de tableau à cette variable, puis en utilisant cette variable en dehors de la fonction. Par exemple.

create_array() {
  local  __resultArgArray=$1
  local my_list=("a" "b" "c")
  eval $__resultArgArray="("${my_list[@]}")"
}

my_algorithm() {
  create_array result
  echo "Total elements in the array: ${#result[@]}"
  for i in "${result[@]}"
  do
    echo $i
  done
}

my_algorithm
1
MNA

Si vos données source sont formatées avec chaque élément de la liste sur une ligne distincte, la commande intégrée mapfile constitue un moyen simple et élégant de lire une liste dans un tableau:

$ list=$(ls -1 /usr/local)           # one item per line

$ mapfile -t arrayVar <<<"$list"     # -t trims trailing newlines

$ declare -p arrayVar | sed 's#\[#\n[#g'
declare -a arrayVar='(
[0]="bin"
[1]="etc"
[2]="games"
[3]="include"
[4]="lib"
[5]="man"
[6]="sbin"
[7]="share"
[8]="src")'

Notez que, comme avec read intégré, vous ne devriez * normalement pas utiliser mapfile dans un pipeline (ou sous-shell) car la variable de tableau affectée ne serait pas disponible pour les instructions suivantes (* sauf si le contrôle de travail bash est désactivé et shopt -s lastpipe est réglé).

$ help mapfile
mapfile: mapfile [-n count] [-O Origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
    Read lines from the standard input into an indexed array variable.

    Read lines from the standard input into the indexed array variable ARRAY, or
    from file descriptor FD if the -u option is supplied.  The variable MAPFILE
    is the default ARRAY.

    Options:
      -n count  Copy at most COUNT lines.  If COUNT is 0, all lines are copied.
      -O Origin Begin assigning to ARRAY at index Origin.  The default index is 0.
      -s count  Discard the first COUNT lines read.
      -t                Remove a trailing newline from each line read.
      -u fd             Read lines from file descriptor FD instead of the standard input.
      -C callback       Evaluate CALLBACK each time QUANTUM lines are read.
      -c quantum        Specify the number of lines read between each call to CALLBACK.

    Arguments:
      ARRAY             Array variable name to use for file data.

    If -C is supplied without -c, the default quantum is 5000.  When
    CALLBACK is evaluated, it is supplied the index of the next array
    element to be assigned and the line to be assigned to that element
    as additional arguments.

    If not supplied with an explicit Origin, mapfile will clear ARRAY before
    assigning to it.

    Exit Status:
    Returns success unless an invalid option is given or ARRAY is readonly or
    not an indexed array.
0
RashaMatt