【问题标题】:how to return an array from a script in Bash?如何从 Bash 中的脚本返回数组?
【发布时间】:2014-08-13 16:23:16
【问题描述】:

假设我有一个名为“Hello”的脚本。类似:

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

我想在另一个脚本中做这样的事情:

tmp=(`Hello`)

我需要的结果是:

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

我得到了

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

或者换句话说,每个单词都放在 tmp 数组中的不同位置。 我如何得到我需要的结果?

【问题讨论】:

  • 你能让Hello 成为一个函数而不是一个单独的脚本吗?
  • 好吧,我可能不得不在 2 个不同的脚本中使用它,所以我宁愿使用一个脚本,而不是两次编写函数。

标签: arrays bash


【解决方案1】:

将其作为 NUL 分隔的流发送:

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

...另一方面,从该流中读取:

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

这通常与进程替换一起使用;在下面的示例中,初始代码位于以generate_an_array 调用的命令(无论是函数还是外部进程)中:

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

您还可以使用declare -p 发出一个字符串,该字符串可以是evaled 以获取内容:

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

...而且,在另一边...

eval "$(generate_an_array)"

但是,这不太可取——它不能移植到除 bash 之外的编程语言(而几乎所有语言都可以读取 NUL 分隔的流),并且它要求接收程序信任发送程序返回 @987654329 @结果而不是恶意内容。

【讨论】:

  • 好吧,因为我们在课堂上几乎没有见过这些,我想我不能使用它。但我想我找到了解决问题的方法
  • @littlerunaway,你的班级不会让你从外部资源中学到任何东西?那是……愚蠢;此答案中使用的所有内容都包含在 bash 手册中,我希望您的班级会鼓励您将其用作参考。
  • bash 是课程中相对较小的一部分。我想他们现在不希望我们深入研究,我们在课堂上看到的一切都应该足够了
【解决方案2】:

尽管有一些变通方法,但您不能真正从 bash 函数或脚本“返回”数组,因为“返回”值的正常方式是将其作为字符串发送到 stdout 并让调用者使用命令替换捕获它。 [注 1] 这对于简单的字符串或非常简单的数组(例如数字数组,其中元素不能包含空格)都可以,但它确实不是发送结构化数据的好方法。

有一些变通方法,例如打印带有特定分隔符的字符串(特别是使用 NUL 字节),可以由调用者解析,或者以可执行 bash 语句的形式,调用者可以使用 @987654322 对其进行评估@,但总的来说,最简单的机制是要求调用者提供可以放置值的数组变量的名称。这仅适用于 bash 函数,因为脚本无法修改调用者的环境,并且仅适用于在父进程中直接调用的函数,因此不适用于管道。实际上,这是一种类似于 read 内置函数和其他一些 bash 内置函数所使用的机制。

这是一个简单的例子。函数split 接受三个参数:数组名、分隔符和字符串:

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

例如:

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

注意事项:

  1. 任何函数或脚本都有状态返回,它是一个小整数;这是returnexit 特殊形式实际返回的内容。但是,状态返回大多是布尔值,当然不能携带结构化值。

【讨论】:

  • +1。可能会提到 namevars 作为更有趣案例的技术(在 bash 4.3+ 或 ksh93 中可用)。
【解决方案3】:

你好.sh

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

其他.sh

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

如果你真的想要一个函数吐出你的脚本将捕获的值,这样做:

你好.sh

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

其他.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]}"

【讨论】:

  • 至少应该明确说明(后面的代码不适用于包含文字换行符的数组值)。
猜你喜欢
  • 2018-07-02
  • 2018-04-20
  • 2017-02-07
  • 2018-06-25
  • 2011-04-09
  • 1970-01-01
  • 2012-04-22
  • 2021-12-03
  • 1970-01-01
相关资源
最近更新 更多