development

전역을 사용하지 않고 bash에서 배열을 반환하는 방법은 무엇입니까?

big-blog 2020. 11. 11. 20:25
반응형

전역을 사용하지 않고 bash에서 배열을 반환하는 방법은 무엇입니까?


배열을 만드는 함수가 있고 배열을 호출자에게 반환하고 싶습니다.

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

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

이것으로 확장 된 문자열 만 얻습니다. 전역을 사용하지 않고 my_list를 어떻게 "반환"할 수 있습니까?


전역에 어떤 문제가 있습니까?

배열을 반환하는 것은 실제로 실용적이지 않습니다. 많은 함정이 있습니다.

즉, 변수 이름이 같은 경우에도 작동하는 한 가지 기술이 있습니다.

$ 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

위의 배쉬 버전 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
}

호출되는 함수의 표준 출력을 얻기 위해 명령 대체 $()필요하지 않기 때문에 이것은 더 우아하고 효율적인 접근 방식 입니다. 함수가 둘 이상의 출력을 반환하는 경우에도 도움이됩니다. 출력 개수만큼 nameref를 사용할 수 있습니다.


다음은 Bash 매뉴얼이 nameref에 대해 말하는 내용입니다.

A variable can be assigned the nameref attribute using the -n option to the declare or local builtin commands (see Bash Builtins) to create a nameref, or a reference to another variable. This allows variables to be manipulated indirectly. Whenever the nameref variable is referenced, assigned to, unset, or has its attributes modified (other than using or changing the nameref attribute itself), the operation is actually performed on the variable specified by the nameref variable’s value. A nameref is commonly used within shell functions to refer to a variable whose name is passed as an argument to the function. For instance, if a variable name is passed to a shell function as its first argument, running

함수 내에서 -n ref = $ 1 선언은 값이 첫 번째 인수로 전달 된 변수 이름 인 nameref 변수 ref를 만듭니다. ref에 대한 참조 및 할당, 속성에 대한 변경은 이름이 $ 1로 전달 된 변수에 대한 참조, 할당 및 속성 수정으로 처리됩니다.


Bash는 데이터 구조를 반환 값으로 전달할 수 없습니다. 반환 값은 0-255 사이의 숫자 종료 상태 여야합니다. 그러나 원하는 경우 명령 또는 프로세스 대체를 사용하여 명령을 eval 문에 전달할 수 있습니다.

IMHO, 이것은 문제의 가치가 거의 없습니다. Bash에서 데이터 구조를 전달해야하는 경우 전역 변수를 사용하십시오. 하지만 어떤 이유로 그렇게하고 싶지 않다면 위치 매개 변수의 관점에서 생각해보십시오.

전역 변수 대신 위치 매개 변수를 사용하도록 예제를 쉽게 다시 작성할 수 있습니다.

use_array () {
    for idx in "$@"; 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 를 전역으로 설정하고 ( 로컬 키워드 를 제거하여 ) my_algorithmunset my_list 끝에 추가 하여 정리합니다.


Matt McClure가 개발 한 기술을 사용하십시오. 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 "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

출력은 다음과 같습니다.

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

당신은 당신의 원래 솔루션을 그렇게 멀리하지 않았습니다. 몇 가지 문제가 있었고 쉼표를 구분 기호로 사용했으며 반환 된 항목을 목록으로 캡처하지 못했습니다. 다음을 시도해보십시오.

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

'declare -p'내장을 기반으로하는 순수한 bash, 최소한의 강력한 솔루션-미친 전역 변수없이

이 접근 방식에는 다음 세 단계가 포함됩니다.

  1. 'declare -p'로 배열을 변환하고 출력을 변수에 저장하십시오. 명령문
    myVar="$( declare -p myArray )"
    의 출력을 declare -p사용하여 배열을 다시 만들 수 있습니다. 예를 들어의 출력은 declare -p myVar다음과 같습니다.
    declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
  2. echo 내장을 사용하여 변수를 함수에 전달하거나 거기에서 다시 전달하십시오.
    • 변수를 에코 할 때 배열 필드의 whitspaces를 보존하기 위해 IFS는 일시적으로 제어 문자 (예 : 수직 탭)로 설정됩니다.
    • 변수에서 선언문의 오른쪽 만 에코됩니다. 이는 $ {parameter # word} 형식의 매개 변수 확장을 통해 수행 할 수 있습니다. 위의 예와 같이 :${myVar#*=}
  3. 마지막으로 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'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

예제 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")'

유용한 예 : 함수에서 배열 반환

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

[ 참고 : 다음은의 편집으로 거부되었습니다 이 답변나에게 아무 의미가없는 이유 (편집이 된 이후에 하지 , 내가 그것을 분리를 만들기 위해 제안을 데려 갈거야, 그래서 게시물의 작성자를 해결하기위한 내용을 담고 있습니다!) 대답.]

의 간단한 구현 매트 맥 클루 어의 기술의 스티브 Zobell의 적응은 내장의 bash를 사용합니다 (이후 4 == 버전 ) readarray RastaMatt에 의해 제안 런타임에 배열로 변환 할 수있는 배열의 표현을 만들 수 있습니다. (모두 참고 readarray하고 mapfile동일한 코드의 이름을 지정합니다.) 그것은 여전히 (파이프에서 함수의 사용을 허용) 전역을 방지하고, 여전히 불쾌한 문자를 처리합니다.

좀 더 완전하게 개발되었지만 (예 : 더 많은 모듈화) 여전히 장난감 예제는 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 "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 ...

실행 /tmp/junk1.sh: 출력은

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

Note 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'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 ...

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

나는 다양한 구현을 시도했지만 공백이있는 요소가있는 배열을 보존하지 않았습니다 echo.

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

해결책

그런 다음 Dennis Williamson의 대답을 보았습니다 . 나는 그의 방법을 다음 함수에 통합하여 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

최근에 비슷한 기능이 필요했기 때문에 다음은 RashaMattSteve Zobell 의 제안을 혼합 한 것입니다 .

  1. 각 배열 / 목록 요소를 함수 내에서 별도의 줄로 에코
  2. 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=("$@")
  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

최근에 함수가 호출 스택의 상위 함수에 선언 된 변수에 직접 액세스 할 수 있다는 점에서 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[@]}"

다음은이 코드의 출력입니다. 프로그램 출력

함수시 request_array의 호출 get_an_array , get_an_array를 직접 설정할 수 인 myArr 에 로컬 변수 request_array를 . 이후 인 myArr이 함께 생성되어 declare, 그것의 로컬 request_array 따라서 범위를 벗어나 request_array 복귀한다.

이 솔루션은 문자 그대로 값을 반환하지는 않지만 전체적으로 보면 진정한 함수 반환 값의 약속을 충족하는 것이 좋습니다.


다음은 외부 배열 참조 및 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')
}

이것은 단순히 배열 변수를 함수에 전달하고 배열 값을이 변수에 할당 한 다음 함수 외부에서이 변수를 사용하여 수행 할 수도 있습니다. 예를 들면.

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

소스 데이터가 별도의 줄에 각 목록 요소로 형식이 지정된 경우 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.

당신은 이것을 시도 할 수 있습니다

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

y가 찾은 가장 쉬운 방법

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

result=($(my_function))

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

참고 URL : https://stackoverflow.com/questions/10582763/how-to-return-an-array-in-bash-without-using-globals

반응형