简体   繁体   English

如何从Bash中的脚本返回一个数组?

[英]how to return an array from a script in Bash?

suppose I have a script called 'Hello'. 假设我有一个名为'Hello'的脚本。 something like: 就像是:

array[0]="hello world"
array[1]="goodbye world"
echo ${array[*]}

and I want to do something like this in another script: 我想在另一个脚本中做这样的事情:

tmp=(`Hello`)

the result I need is: 我需要的结果是:

echo ${tmp[0]}  #prints "hello world"
echo ${tmp[1]}  #prints "goodbye world"

instead I get 相反,我得到了

echo ${tmp[0]}  #prints "hello"
echo ${tmp[1]}  #prints "world"

or in other words, every word is put in a different spot in the tmp array. 换句话说,每个单词都放在tmp数组中的不同位置。 how do I get the result I need? 我如何得到我需要的结果?

Emit it as a NUL-delimited stream: 将其作为NUL分隔的流发送:

printf '%s\0' "${array[@]}"

...and, in the other side, read from that stream: ......而在另一方面,从该流中读取:

array=()
while IFS= read -r -d '' entry; do
  array+=( "$entry" )
done

This often comes in handy in conjunction with process substitution; 这通常与过程替换一起派上用场; in the below example, the initial code is in a command (be it a function or an external process) invoked as generate_an_array : 在下面的示例中,初始代码位于作为generate_an_array调用的命令(无论是函数还是外部进程)中:

array=()
while IFS= read -r -d '' entry; do
  array+=( "$entry" )
done < <(generate_an_array)

You can also use declare -p to emit a string which can be eval ed to get the content back: 您还可以使用declare -p发出一个字符串,可以对其进行eval以获取内容:

array=( "hello world" "goodbye world" )
declare -p array

...and, on the other side... ......而另一方面......

eval "$(generate_an_array)"

However, this is less preferable -- it's not as portable to programming languages other than bash (whereas almost all languages can read a NUL-delimited stream), and it requires the receiving program to trust the sending program to return declare -p results and not malicious content. 然而,这不太可取 - 它不像bash那样可以移植到编程语言(而几乎所有语言都可以读取NUL分隔的流),并且它要求接收程序信任发送程序以返回declare -p结果和不是恶意内容。

Although there are workarounds, you can't really "return" an array from a bash function or script, since the normal way of "returning" a value is to send it as a string to stdout and let the caller capture it with command substitution. 虽然有解决方法,但你不能真正从bash函数或脚本“返回”一个数组,因为“返回”一个值的正常方法是将它作为字符串发送到stdout并让调用者通过命令替换来捕获它。 [Note 1] That's fine for simple strings or very simple arrays (such as arrays of numbers, where the elements cannot contain whitespace), but it's really not a good way to send structured data. [注1]对于简单的字符串或非常简单的数组(例如数字数组,其中元素不能包含空格),这很好,但它实际上不是发送结构化数据的好方法。

There are workarounds, such as printing a string with specific delimiters (in particular, with NUL bytes) which can be parsed by the caller, or in the form of an executable bash statement which can be evaluated by the caller with eval , but on the whole the simplest mechanism is to require that the caller provide the name of an array variable into which the value can be placed. 有一些解决方法,例如打印带有特定分隔符(特别是NUL字节)的字符串,可以由调用者解析,或者以可执行bash语句的形式打印,可以由调用者使用eval ,但是整个最简单的机制是要求调用者提供可以放置值的数组变量的名称。 This only works with bash functions, since scripts can't modify the environment of the caller, and it only works with functions called directly in the parent process, so it won't work with pipelines. 这仅适用于bash函数,因为脚本不能修改调用者的环境,并且它只适用于父进程中直接调用的函数,因此它不适用于管道。 Effectively, this is a mechanism similar to that used by the read built-in, and a few other bash built-ins. 实际上,这是一种类似于read内置函数和其他一些bash内置函数的机制。

Here's a simple example. 这是一个简单的例子。 The function split takes three arguments: an array name, a delimiter, and a string: 函数split有三个参数:数组名称,分隔符和字符串:

split ()  { 
  IFS=$2 read -a "$1" -r -d '' < <(printf %s "$3")
}

eg: 例如:

$ # Some text
$ lorem="Lorem ipsum dolor
sit amet, consectetur
adipisicing elit, sed do
eiusmod tempor incididunt"
# Split at the commas, putting the pieces in the array phrase
$ split phrase "," "$lorem"
# Print the pieces in a way that you can see the elements.
$ printf -- "--%s\n" "${phrase[@]}"
--Lorem ipsum dolor
sit amet
-- consectetur
adipisicing elit
-- sed do
eiusmod tempor incididunt

Notes: 笔记:

  1. Any function or script does have a status return, which is a small integer; 任何函数或脚本都有一个状态返回,这是一个小整数; this is what is actually returned by the return and exit special forms. 这是returnexit特殊表单实际返回的内容。 However, the status return mostly works as a boolean value, and certainly cannot carry a structured value. 但是,状态返回主要用作布尔值,当然不能携带结构化值。

hello.sh hello.sh

declare -a array       # declares a global array variable
array=(
    "hello world"
    "goodbye world"
)

other.sh other.sh

. hello.sh
tmp=( "${array[@]}" )  # if you need to make a copy of the array
echo "${tmp[0]}"
echo "${tmp[1]}"

If you truly want a function to spit out values that your script will capture, do this: 如果您确实希望函数吐出脚本将捕获的值,请执行以下操作:

hello.sh hello.sh

#!/bin/bash
array=(
    "hello world"
    "goodbye world"
)
printf "%s\n" "${array[@]}"

other.sh other.sh

#!/bin/bash
./hello.sh | {
    readarray -t tmp
    echo "${tmp[0]}"
    echo "${tmp[1]}"
}

# or
readarray -t tmp < <(./hello.sh)        
echo "${tmp[0]}"
echo "${tmp[1]}"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM