code

글로벌을 사용하지 않고 bash로 어레이를 반환하려면 어떻게 해야 합니까?

starcafe 2023. 4. 13. 20:59
반응형

글로벌을 사용하지 않고 bash로 어레이를 반환하려면 어떻게 해야 합니까?

어레이를 작성하는 기능이 있어, 어레이를 발신자에게 반환하고 싶다.

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

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

이것으로는 확장된 문자열만 얻을 수 있습니다.글로벌한 기능을 사용하지 않고 my_list를 "반환"하려면 어떻게 해야 합니다.

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
}

명령어를 대체할 필요가 없기 때문에 이 방법은 보다 우아하고 효율적입니다. $()호출되는 함수의 표준 출력을 가져옵니다.또한 함수가 두 개 이상의 출력을 반환하는 경우에도 도움이 됩니다. nameref를 사용하다


nameref에 대한 Bash 매뉴얼에 기재되어 있는 내용은 다음과 같습니다.

변수는 declare 또는 local builtin 명령어(Bash Builtins 참조)에 -n 옵션을 사용하여 nameref 속성을 할당하여 nameref 또는 다른 변수에 대한 참조를 작성할 수 있습니다.이를 통해 변수를 간접적으로 조작할 수 있습니다.nameref 변수가 참조, 할당, 설정 해제 또는 그 Atribut이 변경될 때마다(nameref Atribut 자체를 사용하거나 변경하는 것 이외), 실제로 nameref 변수 값으로 지정된 변수에 대해 작업이 수행됩니다.nameref는 일반적으로 셸 함수 내에서 함수의 인수로 이름이 전달되는 변수를 참조하기 위해 사용됩니다.예를 들어 변수 이름이 첫 번째 인수로 셸 함수에 전달되면

함수 내부에 declare -n ref=$1을 지정하면 nameref 변수 ref가 생성됩니다.이 값은 첫 번째 인수로 전달된 변수 이름입니다.참조할 참조 및 할당 및 해당 속성의 변경은 이름이 $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

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

글로벌 네임스페이스를 오염시키는 데만 관심이 있는 경우 설정되지 않은 빌딘을 사용하여 글로벌 변수를 제거한 후 제거할 수도 있습니다.원래 예를 사용하여 my_list를 글로벌하게 하고(local 키워드를 삭제하여)unset my_list뒷정리를 할 수 있도록 노력하겠습니다.

당신은 원래 해결책에 대해 그렇게 멀리 있지 않았어요.몇 가지 문제가 발생하여 쉼표를 구분자로 사용하고 반환된 항목을 목록에 캡처하지 못했습니다. 다음을 수행하십시오.

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

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+=('"'"$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

'declare -p'를 기본으로 한 순수하고 최소한의 견고한 솔루션.광범위한 글로벌 변수가 필요 없음

이 어프로치에는, 다음의 3개의 순서가 있습니다.

  1. '' - p 'p declare -p - p 'p p pp - p 'p 。
    myVar="$( declare -p myArray )"
    declare -p문을 사용하여 어레이를 다시 만들 수 있습니다.를 들어, 「」의 , 「」의 출력 등입니다.declare -p myVar 수 요.
    declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
  2. 에코 빌트인을 사용하여 변수를 함수에 전달하거나 변수를 함수에서 되돌립니다.
    • 변수를 에코할 때 배열 필드의 화이트스페이스를 유지하기 위해 IFS는 일시적으로 제어 문자(수직 탭 등)로 설정됩니다.
    • 변수의 선언문 오른쪽만 에코됩니다.${parameter #word}는 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")'

최근에 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_arrayrequest_array에 로컬인 myarr 변수를 직접 설정할 수 있습니다.myarr가 생성되었기 때문에declarerequest_array에 로컬이므로 request_array가 반환되면 범위를 벗어납니다.

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

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

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

가지 를 가진 . 공백이 있는 요소를 사용해야 때문입니다. 왜냐하면 이 어레이들은 모두 사용해야 했기 때문입니다.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

최근에 비슷한 기능이 필요했기 때문에, 다음은 RashaMatt와 Steve 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

외부 어레이 참조나 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')
}

(주의:답변편집은 필자가 글을 쓴 사람에게 전달하기 위한 것이 아니기 때문에) 이 답변의 편집으로 다음 내용이 거부되었습니다.따라서 답변으로 하겠습니다.

Steve Zobell이 Matt McClure 기술을 채택한 보다 간단한 구현은 bash 내장(버전 == 4 이후)을 사용합니다.readarray 실행어레이로 변환할 수 있는 어레이 표현을 작성하도록 RastaMatt에 의해 제안되었습니다.(양쪽 모두readarray ★★★★★★★★★★★★★★★★★」mapfile을 사용법)여전히 글로벌(파이프 내 기능 사용 가능)을 피하고 지저분한 문자를 처리합니다.

보다 완전하게 개발된 (예를 들어 모듈화 등)그러나 아직 Kinda-toy의 예에 대해서는 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!
!#$^%^&(*)_^&% ^$#@:"<>?/.,\\"'

: ★lines_to_array_representation는 공백 행도 처리합니다.쾅쾅거리다

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!

됩니다.eval IFS로로 합니다.\n이 방법에는 적어도2가지 좋은 방법이 있습니다.

사용 1) echo ★★★★★★★★★★★★★★★★★」mapfile

의 각 , '어레이의 각 항목'을 사용할 수 .mapfile열로변 변환: :

outputArray()
{
    for i
    {
        echo "$i"
    }
}

declare -a arr=( 'qq' 'www' 'ee rr' )
mapfile -t array < <(outputArray "${arr[@]}")
for i in "${array[@]}"
do
   echo "i=$i"
done

하려면 , 「 를 추가합니다.(( $# == 0 )) && readarray -t temp && set "${temp[@]}" && unset temp출력 배열의 맨 위로 이동합니다.stdin으로 합니다.

사용 2) 사용법declare -p ★★★★★★★★★★★★★★★★★」sed

이 작업은 다음 방법으로도 수행할 수 있습니다.declare -p ★★★★★★★★★★★★★★★★★」sedmapfile.

outputArray()
{
    (( $# == 0 )) && readarray -t temp && set "${temp[@]}" && unset temp
    for i; { echo "$i"; }
}

returnArray()
{
    local -a arr=()
    (( $# == 0 )) && readarray -t arr || for i; { arr+=("$i"); }
    declare -p arr | sed -e 's/^declare -a [^=]*=//'
}

declare -a arr=( 'qq' 'www' 'ee rr' )

declare -a array=$(returnArray "${arr[@]}")
for i in "${array[@]}"
do
   echo "i=$i"
done

declare -a array=$(outputArray "${arr[@]}" | returnArray)
echo
for i in "${array[@]}"
do
    echo "i=$i"
done

declare -a array < <(outputArray "${arr[@]}" | returnArray)
echo
for i in "${array[@]}"
do
   echo "i=$i"
done

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

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

가장 쉬운 방법은

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

result=($(my_function))

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

이 경우에도 하실 수 있습니다.declare -p declare -a값이 문자열(문자열 외부에 진정한 패런이 없는 경우):

# return_array_value returns the value of array whose name is passed in.
#   It turns the array into a declaration statement, then echos the value
#   part of that statement with parentheses intact.  You can use that
#   result in a "declare -a" statement to create your own array with the
#   same value.  Also works for associative arrays with "declare -A".
return_array_value () {
  declare Array_name=$1  # namespace locals with caps to prevent name collision
  declare Result

  Result=$(declare -p $Array_name)  # dehydrate the array into a declaration
  echo "${Result#*=}"               # trim "declare -a ...=" from the front
}

# now use it.  test for robustness by skipping an index and putting a
# space in an entry.
declare -a src=([0]=one [2]="two three")
declare -a dst="$(return_array_value src)"    # rehydrate with double-eval

declare -p dst
> declare -a dst=([0]="one" [2]="two three")  # result matches original

확인 중 " " " "declare -p dst 율율declare -a dst=([0]="one" [2]="two three")"는, 이 방식이, 스퍼스 어레이와 IFS 문자(스페이스)를 가지는 엔트리를 모두 올바르게 처리하는 것을 나타내고 있습니다.

입니다.declare -p쾅쾅거리다은 '에서 'declare'로 그 합니다.${Result#*=} 안에로 두겠습니다.([0]="one" [2]="two three").

그런 다음 어레이 이름을 선택하는 자신의 선언문에 해당 값을 입력하여 어레이를 재공급합니다.이라는 합니다.dst어레이 선언은 선언 자체의 진정한 괄호가 아니라 문자열 안에 괄호가 있는 문자열입니다.를 들어, 예를 들어 다음과 같습니다. declare -a dst=( "true parens outside string" ) 하면 발동됩니다.declare먼저 평가하겠습니다declare -a dst=([0]="one" [2]="two three")그러면 스테이트먼트로서 평가됩니다.

은 '이중평가'에하다는 점에 하시기 바랍니다.-a ★★★★★★★★★★★★★★★★★」-Adeclose옵션을 합니다.

이 할 수 요. 그냥 .변경만 하면 됩니다.-a로로 합니다.-A.

이 메서드는 stdout에 의존하기 때문에 다른 사용자가 지적한 바와 같이 파이프라인과 같은 서브셸 경계를 넘어 작동합니다.

이 방법에 대해서는 블로그 투고에서 자세히 설명합니다.

가 각 되어 있는 , " " " " " " " " " " " " " "mapfile로 읽는 간단하고 우아한 입니다.builtin 목 、 목은 、 inin、 in built built built built built built 。

$ 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 would anyorly*는 보통 사용하지 않습니다.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

배열 값을 설정하기 위해 코드 블록에 배관하는 것이 좋습니다.이 전략은 POSIX와 호환되므로 Bash와 Zsh를 모두 사용할 수 있으며 게시된 솔루션과 같은 부작용의 위험을 감수하지 않습니다.

i=0                   # index for our new array
declare -a arr        # our new array

# pipe from a function that produces output by line
ls -l | { while read data; do i=$i+1; arr[$i]="$data"; done }

# example of reading that new array
for row in "${arr[@]}"; do echo "$row"; done

하면 될 것 같아요.zsh ★★★★★★★★★★★★★★★★★」bash공백이나 특수문자의 영향을 받지 않습니다.OP의 경우 출력은 에코에 의해 변환되기 때문에 실제로는 배열을 출력하는 것이 아니라 출력하는 것입니다(다른 셸 함수에서 설명한 바와 같이 값이 아닌 상태를 반환합니다.Pipeline Ready (파이프라인이 준비되었습니다)

create_array() {
  local my_list=("a", "b", "c")
  for row in "${my_list[@]}"; do
    echo "$row"
  done
}

my_algorithm() {
  i=0
  declare -a result
  create_array | { while read data; do i=$i+1; result[$i]="$data"; done }
}

뺄 수 요.create_array my_algorithm 두 .

create_array | my_algorithm

를 한 최신 Bash @Q'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:

#!/usr/bin/env bash

return_array_elements() {
  local -a foo_array=('1st one' '2nd two' '3rd three')
  printf '%s\n' "${foo_array[@]@Q}"
}

use_array_elements() {
  local -a bar_array="($(return_array_elements))"
  # Display declareation of bar_array 
  # which is local to this function, but whose elements
  # hahaves been returned by the return_array_elements function
  declare -p bar_array
}

use_array_elements

출력:

declare -a bar_array=([0]="1st one" [1]="2nd two" [2]="3rd three")

접근방식은 우아하지만 글로벌 어레이를 작성할 수 있습니다.declare -g 기능 내에서 기능 범위 에서 볼 수 있어야 합니다.

create_array() {
  declare -ag result=("a", "b", "c")
}

my_algorithm() {
  create_array
  echo "${result[@]}"
}

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

반응형