Подтвердить что ты не робот

Как вернуть массив в bash без использования глобальных переменных?

У меня есть функция, которая создает массив, и я хочу вернуть массив вызывающему:

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

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

При этом я получаю только расширенную строку. Как я могу "вернуть" my_list, не используя ничего глобального?

4b9b3361

Ответ 1

Что случилось с глобалами?

Возвращаемые массивы действительно непрактичны. Есть много подводных камней.

Тем не менее, здесь один метод, который работает, если он ОК, что переменная имеет одно и то же имя:

$ 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

Команды declare -p (кроме одного в f()) используются для отображения состояния массива для демонстрационных целей. В f() он используется как механизм для возврата массива.

Если вам нужен массив с другим именем, вы можете сделать что-то вроде этого:

$ 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

Ответ 2

В Bash версии 4.3 и выше вы можете использовать nameref, чтобы вызывающий мог передать имя массива, а вызываемый может использовать nameref для косвенного заполнения именованного массива.

#!/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

Производит вывод:

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

Вы также можете заставить функцию обновить существующий массив:

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
}

Это более элегантный и эффективный подход, поскольку нам не требуется подстановка команд $() для получения стандартного вывода вызываемой функции. Также помогает, если функция возвращает более одного вывода - мы можем просто использовать столько имен, сколько и количество выходов.


Вот что говорит Bash Manual о nameref:

Переменной можно присвоить атрибут nameref, используя опцию -n для команд объявления или локальных встроенных команд (см. Раздел Встроенные команды Bash), чтобы создать ссылку на имя или ссылку на другую переменную. Это позволяет косвенно манипулировать переменными. Всякий раз, когда на переменную nameref ссылаются, присваивают, отменяют или изменяют ее атрибуты (кроме использования или изменения самого атрибута nameref), операция фактически выполняется над переменной, указанной значением переменных nameref. Nameref обычно используется в функциях оболочки для ссылки на переменную, имя которой передается в качестве аргумента функции. Например, если имя переменной передается функции оболочки в качестве первого аргумента, выполняется

Объявление функции -n ref = $ 1 внутри функции создает переменную nameref ref, значением которой является имя переменной, переданное в качестве первого аргумента. Ссылки и назначения для ref и изменения к его атрибутам рассматриваются как ссылки, назначения и модификации атрибутов для переменной, имя которой было передано как $ 1.

Ответ 3

Bash не может передавать структуры данных в качестве возвращаемых значений. Возвращаемое значение должно быть числовым статусом выхода между 0-255. Однако вы можете использовать команду или подстановку процессов для передачи команд в eval-инструкцию, если вы так склонны.

Это редко стоит того, ИМХО. Если вы должны передать структуры данных в Bash, используйте глобальную переменную - для чего они предназначены. Если вы не хотите этого делать по какой-то причине, подумайте о позиционных параметрах.

Ваш пример может быть легко переписан для использования позиционных параметров вместо глобальных переменных:

use_array () {
    for idx in "[email protected]"; do
        echo "$idx"
    done
}

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

Все это создает определенную сумму ненужной сложности. Bash функции, как правило, работают лучше всего, когда вы относитесь к ним скорее как процедуры с побочными эффектами и вызываете их последовательно.

# 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

Если все, что вас беспокоит, загрязняет ваше глобальное пространство имен, вы также можете использовать unset builtin для удаления глобальной переменной после того, как вы закончите с ней. Используя исходный пример, пусть my_list будет глобальным (удалив локальное ключевое слово) и добавьте unset my_list в конец my_algorithm для очистки после себя.

Ответ 4

Используйте технику, разработанную Мэттом МакКлюром: http://notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html

Избегая глобальных переменных, вы можете использовать эту функцию в трубе. Вот пример:

#!/bin/bash

makeJunk()
{
   echo 'this is junk'
   echo '#more junk and "[email protected]" 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

Выход:

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

Ответ 5

Вы не так далеко от своего оригинального решения. У вас было несколько проблем, вы использовали запятую в качестве разделителя, и вам не удалось захватить возвращенные элементы в список, попробуйте следующее:

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

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

Учитывая комментарии о встроенных пространствах, несколько настроек, использующих IFS, могут решить следующее:

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[*]}" 
}

Ответ 6

Чистое bash, минимальное и надежное решение, основанное на встроенном объявлении -p, без безумных глобальных переменных

Этот подход включает в себя следующие три этапа:

  • Преобразуйте массив с 'declare -p' и сохраните вывод в переменной.
    myVar="$( declare -p myArray )"
    Вывод оператора declare -p может использоваться для воссоздания массива. Например, вывод declare -p myVar может выглядеть следующим образом:
    declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
  • Используйте встроенный echo, чтобы передать переменную функции или передать ее обратно.
    • Чтобы сохранить whitspaces в полях массива при повторении этой переменной, IFS временно устанавливается на управляющий символ (например, вертикальную вкладку).
    • Следует указывать только правую часть инструкции declare в переменной - это может быть достигнуто путем расширения параметра формы ${parameter # word}. Что касается вышеприведенного примера: ${myVar#*=}
  • Наконец, заново создайте массив, в который он передается, используя eval и встроенные функции declare -a.

Пример 1 - вернуть массив из функции

#!/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

Результат примера 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")'

Пример 2 - передать массив функции

#!/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 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

Выход из примера 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")'

Ответ 7

Полезный пример: вернуть массив из функции

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

Ответ 8

[ Примечание: следующее было отклонено как редактирование этого ответа по причинам, которые не имеют смысла для меня (так как редактирование не предназначалось для автора сообщения!), Поэтому я принимаю предложение сделать его отдельным ответ.]

В более простой реализации адаптации Стива Зобелла к методу Мэтта МакКлюра используется встроенный (начиная с версии = 4) readarray предложенный RastaMatt, для создания представления массива, который может быть преобразован в массив во время выполнения. (Обратите внимание, что readarray и mapfile называют readarray и тот же код.) Он по-прежнему избегает глобальных переменных (допускает использование функции в конвейере) и по-прежнему обрабатывает неприятные символы.

Для некоторых более полностью разработанных (например, более модульных), но все еще довольно забавных примеров, смотрите bash_pass_arrays_between_functions. Ниже приведены несколько легко исполняемых примеров, приведенных здесь, чтобы избежать модераторов, обсуждающих внешние ссылки.

Вырежьте следующий блок и вставьте его в терминал bash для создания /tmp/source.sh и /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 "[email protected]" 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 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 ...

Запустите /tmp/junk1.sh: вывод должен быть

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

Обратите внимание, что lines_to_array_representation также обрабатывает пустые строки. Попробуйте вставить следующий блок в ваш 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 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 ...

Запустите /tmp/junk2.sh @/tmp/junk2.sh. Ваш вывод должен быть похож на мой:

'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 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!

Ответ 9

Я пробовал различные реализации, и ни один из сохранившихся массивов, у которых были элементы с пробелами... потому что все они должны были использовать echo.

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

Решение

Затем я наткнулся на ответ Дениса Уильямсона. Я включил его метод в следующие функции, чтобы они могли: a) принять произвольный массив и b) использовать для передачи, дублирования и добавления массивов.

# 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\ *=}
}  

Затем другие функции могут возвращать массив с помощью уловимых выходных или косвенных аргументов.

# 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

Ответ 10

Мне нужна была аналогичная функциональность в последнее время, поэтому следующее представляет собой сочетание предложений, сделанных RashaMatt и Steve Zobell.

  • эхо каждого элемента массива/списка в виде отдельной строки из функции
  • используйте mapfile для чтения всех элементов массива/списка, эхо-сигнала которых выполняет функция.

Насколько я вижу, строки сохраняются целыми и сохраняются пробелы.

#!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

Еще несколько вариантов...

#!/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=("[email protected]")
  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

Ответ 11

Недавно я обнаружил причуду в BASH, что функция имеет прямой доступ к переменным, объявленным в функциях выше в стеке вызовов. Я только начал размышлять над тем, как использовать эту функцию (она обещает как преимущества, так и опасности), но одно очевидное приложение - это решение духа этой проблемы.

Я также предпочел бы получить возвращаемое значение, а не использовать глобальную переменную при делегировании создания массива. Есть несколько причин для моих предпочтений, среди которых следует избегать возможного нарушения существующей ценности и избежать оставления значения, которое может быть недействительным при последующем доступе. Хотя есть обходные пути для этих проблем, самым простым является то, что переменная выходит за пределы области действия, когда код завершается с ней.

Мое решение гарантирует, что массив доступен по мере необходимости и отбрасывается, когда функция возвращается, и оставляет без изменений глобальную переменную с тем же именем.

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

Вот вывод этого кода: program output

Когда функция request_array вызывает get_an_array, get_an_array может напрямую установить переменную myarr, которая является локальной для request_array. Поскольку myarr создается с declare, он является local request_array и, таким образом, выходит из области действия, когда request_array возвращается.

Хотя это решение буквально не возвращает значение, я предлагаю, что он взят в целом, он удовлетворяет обещаниям истинного возвращаемого значения функции.

Ответ 12

Вот решение без ссылок на внешние массивы и манипуляций с IFS:

# add one level of single quotes to args, eval to remove
squote () {
    local a=("[email protected]")
    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')
}

Ответ 13

Это также можно сделать, просто передав переменную массива функции и назначив значения массива этому var, затем используйте этот var вне функции. Например.

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

Ответ 14

Если исходные данные форматируются с каждым элементом списка в отдельной строке, то встроенный mapfile представляет собой простой и элегантный способ чтения списка в массив:

$ 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")'

Обратите внимание, что, как и в случае с read встроенным, вы обычно не использовали бы mapfile в конвейере (или в подоболочке), потому что назначенная переменная массива была бы недоступна для последующих операторов (* если bash отключено и shopt -s lastpipe).

$ 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.

Ответ 15

Вы можете попробовать это

my_algorithm() {
  create_array list
  for element in "${list[@]}"
  do
    echo "${element}"
  done
}

create_array() {
  local my_list=("1st one" "2nd two" "3rd three")

  eval "${1}=()"
  for element in "${my_list[@]}"
  do
    eval "${1}+=(\"${element}\")"
  done
}

my_algorithm

Выходной сигнал

1st one
2nd two
3rd three

Ответ 16

Самый простой способ найти

my_function()
{
    array=(one two three)
    echo ${array[@]}
}

result=($(my_function))

echo ${result[0]}
echo ${result[1]}
echo ${result[2]}