如何在不使用全局变量的情况下在 bash 中返回数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10582763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:05:56  来源:igfitidea点击:

How to return an array in bash without using globals?

arraysbashglobal-variablesparameter-passing

提问by helpermethod

I have a function that creates an array and I want to return the array to the caller:

我有一个创建数组的函数,我想将数组返回给调用者:

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

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

With this, I only get an expanded string. How can I "return" my_list without using anything global?

有了这个,我只能得到一个扩展的字符串。如何在不使用任何全局内容的情况下“返回”my_list?

采纳答案by Paused until further notice.

What's wrong with globals?

全局变量有什么问题?

Returning arrays is really not practical. There are lots of pitfalls.

返回数组真的不切实际。有很多陷阱。

That said, here's one technique that works if it's OK that the variable have the same name:

也就是说,如果变量具有相同的名称,这是一种可行的技术:

$ 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

The declare -pcommands (except for the one in f()are used to display the state of the array for demonstration purposes. In f()it's used as the mechanism to return the array.

declare -p命令(除了一个在f()用于显示该阵列用于演示目的的状态,在f()它用作机制以返回该阵列。

If you need the array to have a different name, you can do something like this:

如果您需要数组具有不同的名称,您可以执行以下操作:

$ 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

回答by codeforester

With Bash version 4.3 and above, you can make use of a namerefso that the caller can pass in the array name and the callee can use a nameref to populate the named array, indirectly.

在 Bash 4.3 及更高版本中,您可以使用nameref以便调用者可以传入数组名称,而被调用者可以使用 nameref间接填充命名数组。

#!/usr/bin/env bash

create_array() {
    local -n arr=             # 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

Produces the output:

产生输出:

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

You could make the function update an existing array as well:

您也可以使函数更新现有数组:

update_array() {
    local -n arr=             # 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
}

This is a more elegant and efficient approach since we don't need command substitution$()to grab the standard output of the function being called. It also helps if the function were to return more than one output - we can simply use as many namerefs as the number of outputs.

这是一种更优雅和有效的方法,因为我们不需要命令替换$()来获取被调用函数的标准输出。如果函数返回多个输出,这也有帮助——我们可以简单地使用与输出数量一样多的名称引用。



Here is what the Bash Manualsays about 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

declare -n ref=$1 inside the function creates a nameref variable ref whose value is the variable name passed as the first argument. References and assignments to ref, and changes to its attributes, are treated as references, assignments, and attribute modifications to the variable whose name was passed as $1.

可以使用声明或本地内置命令(请参阅 Bash 内置命令)的 -n 选项为变量分配 nameref 属性,以创建 nameref 或对另一个变量的引用。这允许间接操作变量。每当 nameref 变量被引用、分配给、取消设置或修改其属性(而不是使用或更改 nameref 属性本身)时,操作实际上是在 nameref 变量的值指定的变量上执行的。nameref 通常在 shell 函数中用于引用一个变量,该变量的名称作为参数传递给函数。例如,如果变量名称作为第一个参数传递给 shell 函数,则运行

函数中的 declare -n ref=$1 创建一个 nameref 变量 ref,其值是作为第一个参数传递的变量名称。对 ref 的引用和赋值,以及对其属性的更改,被视为对其名称作为 $1 传递的变量的引用、赋值和属性修改。

回答by Todd A. Jacobs

Bash can't pass around data structures as return values. A return value must be a numeric exit status between 0-255. However, you can certainly use command or process substitution to pass commands to an eval statement if you're so inclined.

Bash 不能将数据结构作为返回值传递。返回值必须是 0-255 之间的数字退出状态。但是,如果您愿意,您当然可以使用命令或进程替换将命令传递给 eval 语句。

This is rarely worth the trouble, IMHO. If you must pass data structures around in Bash, use a global variable--that's what they're for. If you don't want to do that for some reason, though, think in terms of positional parameters.

恕我直言,这很少值得麻烦。如果您必须在 Bash 中传递数据结构,请使用全局变量——这就是它们的用途。但是,如果您出于某种原因不想这样做,请考虑位置参数。

Your example could easily be rewritten to use positional parameters instead of global variables:

您的示例可以很容易地重写为使用位置参数而不是全局变量:

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

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

This all creates a certain amount of unnecessary complexity, though. Bash functions generally work best when you treat them more like procedures with side effects, and call them in sequence.

不过,这一切都会造成一定程度的不必要的复杂性。当您将 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

If all you're worried about is polluting your global namespace, you can also use the unset builtinto remove a global variable after you're done with it. Using your original example, let my_listbe global (by removing the localkeyword) and add unset my_listto the end of my_algorithmto clean up after yourself.

如果您担心的只是污染全局命名空间,您还可以在完成后使用unset 内建来删除全局变量。使用您的原始示例,让my_list是全局的(通过删除local关键字)并添加unset my_listmy_algorithm 的末尾以自己清理。

回答by cdarke

You were not so far out with your original solution. You had a couple of problems, you used a comma as a separator, and you failed to capture the returned items into a list, try this:

您的原始解决方案并没有那么远。您遇到了一些问题,您使用逗号作为分隔符,并且未能将返回的项目捕获到列表中,请尝试以下操作:

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

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

Considering the comments about embedded spaces, a few tweaks using IFScan solve that:

考虑到关于嵌入空间的评论,使用一些调整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[*]}" 
}

回答by Steve Zobell

Use the technique developed by Matt McClure: http://notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html

使用 Matt McClure 开发的技术:http: //notes-matthewlmcclure.blogspot.com/2009/12/return-array-from-bash-function-v-2.html

Avoiding global variables means you can use the function in a pipe. Here is an example:

避免全局变量意味着您可以在管道中使用该函数。下面是一个例子:

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

Output is:

输出是:

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

回答by F.M.

A pure bash, minimal and robust solution based on the 'declare -p' builtin — without insane global variables

基于'declare -p'内置函数的纯bash、最小和健壮的解决方案——没有疯狂的全局变量

This approach involves the following three steps:

这种方法包括以下三个步骤:

  1. Convert the array with 'declare -p' and save the output in a variable.
    myVar="$( declare -p myArray )"
    The output of the declare -pstatement can be used to recreate the array. For instance the output of declare -p myVarmight look like this:
    declare -a myVar='([0]="1st field" [1]="2nd field" [2]="3rd field")'
  2. Use the echo builtin to pass the variable to a function or to pass it back from there.
    • In order to preserve whitspaces in array fields when echoing the variable, IFS is temporarly set to a control character (e.g. a vertical tab).
    • Only the right-hand-side of the declare statement in the variable is to be echoed - this can be achieved by parameter expansion of the form ${parameter#word}. As for the example above: ${myVar#*=}
  3. Finally, recreate the array where it is passed to using the eval and the 'declare -a' builtins.
  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 内置函数将变量传递给函数或从函数传回。
    • 为了在回显变量时保留数组字段中的空格,IFS 临时设置为控制字符(例如垂直制表符)。
    • 只有变量中声明语句的右侧会被回显 - 这可以通过 ${parameter#word} 形式的参数扩展来实现。至于上面的例子:${myVar#*=}
  3. 最后,使用 eval 和 'declare -a' 内置函数重新创建传递给它的数组。

Example 1 - return an array from a function

示例 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

Output of Example 1:

示例 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")'


Example 2 - pass an array to a function

示例 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 "" )"

 # 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

Output of Example 2:

示例 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")'

回答by Rafael

Useful example: return an array from function

有用的例子:从函数返回一个数组

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

function StrToArray() {
  IFS=$'\t'; set ; 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

回答by TomRoche

[Note:the following was rejected as an edit of this answerfor reasons that make no sense to me(since the edit was notintended to address the author of the post!), so I'm taking the suggestion to make it a separate answer.]

[注:以下被拒绝作为一个编辑这个答案原因,毫无意义,我(因为编辑是不是,所以我考虑的建议,使之成为独立的旨在解决该帖子的作者!)回答。]

A simpler implementation of Steve Zobell's adaptation of Matt McClure's techniqueuses the bash built-in (since version == 4) readarrayas suggested by RastaMattto create a representation of an array that can be converted into an array at runtime. (Note that both readarrayand mapfilename the same code.) It still avoids globals (allowing use of the function in a pipe), and still handles nasty characters.

一个更简单的实施马特McClure的技术的史蒂夫Zobell的适应使用内置在bash(因为版本== 4readarray由RastaMatt的建议来创建一个数组,可以被转换成在运行时的阵列的表示。(请注意,readarraymapfile命名相同的代码。)它仍然避免使用全局变量(允许在管道中使用该函数),并且仍然处理讨厌的字符。

For some more-fully-developed (e.g., more modularization) but still-kinda-toy examples, see bash_pass_arrays_between_functions. Following are a few easily-executable examples, provided here to avoid moderators b!tching about external links.

对于一些更完全开发(例如,更多模块化)但仍然有点玩具的示例,请参阅bash_pass_arrays_between_functions。以下是一些易于执行的示例,在此提供是为了避免版主窃听外部链接。

Cut the following block and paste it into a bash terminal to create /tmp/source.shand /tmp/junk1.sh:

剪切以下块并将其粘贴到 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 ...

Run /tmp/junk1.sh: output should be

运行/tmp/junk1.sh:输出应该是

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

Note lines_to_array_representationalso handles blank lines. Try pasting the following block into your bash terminal:

注意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 ...

Run /tmp/junk2.sh@ commandline. Your output should be similar to mine:

运行/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!

回答by Matei David

Here is a solution with no external array references and no IFS 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')
}

回答by chuckj

I recently discovered a quirk in BASH in that a function has direct access to the variables declared in the functions higher in the call stack. I've only just started to contemplate how to exploit this feature (it promises both benefits and dangers), but one obvious application is a solution to the spirit of this problem.

我最近在 BASH 中发现了一个怪癖,即函数可以直接访问调用堆栈中较高函数中声明的变量。我才刚刚开始考虑如何利用这个特性(它既有好处也有危险),但一个明显的应用是解决这个问题的精神。

I would also prefer to get a return value rather than using a global variable when delegating the creation of an array. There are several reasons for my preference, among which are to avoid possibly disturbing an preexisting value and to avoid leaving a value that may be invalid when later accessed. While there are workarounds to these problems, the easiest is have the variable go out of scope when the code is finished with it.

我还希望在委托创建数组时获得返回值而不是使用全局变量。我的偏好有几个原因,其中包括避免可能干扰预先存在的值以及避免留下一个在以后访问时可能无效的值。虽然有解决这些问题的方法,但最简单的方法是在代码完成后让变量超出范围。

My solution ensures that the array is available when needed and discarded when the function returns, and leaves undisturbed a global variable with the same name.

我的解决方案确保该数组在需要时可用并在函数返回时被丢弃,并保持一个具有相同名称的全局变量不受干扰。

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

Here is the output of this code: program output

这是这段代码的输出: 程序输出

When function request_arraycalls get_an_array, get_an_arraycan directly set the myarrvariable that is local to request_array. Since myarris created with declare, it is local to request_arrayand thus goes out of scope when request_arrayreturns.

当函数request_array调用get_an_array 时get_an_array可以直接设置request_array本地的myarr变量。由于myarr是用 来创建的,它对于request_array是本地的,因此在request_array返回时超出范围。declare

Although this solution does not literally return a value, I suggest that taken as a whole, it satisfies the promises of a true function return value.

虽然这个解决方案并没有真正返回一个值,但我建议作为一个整体,它满足真正函数返回值的承诺。