TL;DR:直接不支持可导出数组,直到 bash-4.3(包括 bash-4.3),但您可以(有效)通过以下两种方式之一导出数组:
- 对子脚本调用方式的简单修改
- 使用导出的函数来存储数组初始化,只需对子脚本进行简单修改
或者,您可以等到 bash-4.3 发布(截至 2014 年 2 月处于开发/RC 状态,请参阅变更日志中的 ARRAY_EXPORT)。 更新:此功能不是 em> 在 4.3 中启用。如果在构建时定义ARRAY_EXPORT,构建将失败。作者has stated不打算完成这个功能。
首先要了解的是 bash 环境(更准确地说是command execution environment)与 POSIX 环境概念不同。 POSIX environment 是无类型的name=value 对的集合,可以从进程传递给它的子进程in various ways(实际上是IPC 的有限形式)。
bash 执行环境实际上是它的超集,具有类型变量、只读和可导出标志、数组、函数等。这部分解释了为什么set(bash 内置)和env 或printenv 的输出不同。
当您调用另一个 bash shell 时,您正在启动一个新进程,您会失去一些 bash 状态。但是,如果您对脚本进行点源,则该脚本将在相同的环境中运行;或者,如果您通过( ) 运行子shell,环境也会被保留(因为 bash 分叉,保留其完整状态,而不是使用进程环境重新初始化)。
@lesmana 的答案中引用的限制出现了,因为 POSIX 环境只是 name=value 对,没有额外的含义,因此没有一致的方法来编码或格式化类型变量,请参阅下面关于函数 的有趣 bash 怪癖,以及 bash-4.3 中即将发生的变化(放弃了提议的数组功能)。
有几种简单的方法可以做到这一点,使用declare -p(内置)将一些bash环境输出为一组一个或多个declare语句,可用于重建类型和值一个名字”。这是基本的serialisation,但其他一些答案暗示的complexity 却少得多。 declare -p 保留数组索引、稀疏数组和麻烦值的引用。对于数组的简单序列化,您可以逐行转储值,然后使用 read -a myarray 来恢复它(适用于连续的 0 索引数组,因为 read -a 自动分配索引)。
这些方法不需要对您将数组传递到的脚本进行任何修改。
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
bash -c ". .bash_arrays; . otherscript.sh" # source both in the same environment
上述bash -c "..." 形式的变体有时(错误)在 crontab 中用于设置变量。
替代方案包括:
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
BASH_ENV=.bash_arrays otherscript.sh # non-interactive startup script
或者,作为单行:
BASH_ENV=<(declare -p array1 array2) otherscript.sh
最后一个使用进程替换将declare命令的输出作为rc脚本传递。 (此方法仅适用于 bash-4.0 或更高版本:早期版本无条件 fstat() rc 文件,并一次性使用返回到 read() 文件的大小;FIFO 返回大小为 0,因此不能作为希望。)
在 非交互式 shell(即 shell 脚本)中,BASH_ENV 变量指向的文件是 automatically sourced。您必须确保正确调用 bash,可能使用 shebang 显式调用“bash”,而不是 #!/bin/sh,因为 bash 在历史/POSIX 模式下将不支持 BASH_ENV。
如果您的所有数组名称碰巧有一个共同的前缀,您可以使用declare -p ${!myprefix*} 来展开它们的列表,而不是枚举它们。
您可能不应该尝试使用此方法导出和重新导入 整个 bash 环境,一些特殊的 bash 变量和数组是只读的,修改时可能会有其他副作用特殊变量。
(您也可以通过将数组定义序列化为可导出变量并使用eval 来做一些稍微不愉快的事情,但我们不鼓励使用eval ...
$ array=([1]=a [10]="b c")
$ export scalar_array=$(declare -p array)
$ bash # start a new shell
$ eval $scalar_array
$ declare -p array
declare -a array='([1]="a" [10]="b c")'
)
如上所述,有一个有趣的怪癖:通过环境导出函数的特殊支持:
function myfoo() {
echo foo
}
使用export -f 或set +a 启用此行为,将在(进程)环境中导致此行为,使用printenv 可见:
myfoo=() { echo foo
}
变量为functionname(或functioname(),用于向后兼容),其值为() { functionbody }。
当后续的 bash 进程启动时,它将从每个这样的环境变量重新创建一个函数。如果您查看 bash-4.2 源文件 variables.c,您会看到以 () { 开头的变量是经过特殊处理的。 (尽管禁止使用 declare -f 的这种语法创建函数。)更新:“shellshock" 安全问题与此功能有关,现代系统可能会禁用从环境中自动导入函数作为缓解。
如果你继续阅读,你会看到一个#if 0(或#if ARRAY_EXPORT)保护代码,它检查以([ 开头并以) 结尾的变量,以及一条说明“数组变量”的注释可能尚未导出”。 好消息是,在当前开发版本 bash-4.3rc2 中,导出索引数组(非关联)的功能已启用。此功能不太可能启用,如上所述。
我们可以使用它来创建一个函数来恢复所需的任何数组数据:
% function sharearray() {
array1=(a b c d)
}
% export -f sharearray
% bash -c 'sharearray; echo ${array1[*]}'
因此,与之前的方法类似,调用子脚本:
bash -c "sharearray; . otherscript.sh"
或者,您可以通过在某个适当的点添加来有条件地调用子脚本中的sharearray 函数:
[ "`type -t sharearray`" = "function" ] && sharearray
请注意,sharearray 函数中没有 declare -a,如果您这样做,该数组对于函数是隐式的本地,这不是我们想要的。 bash-4.2 支持declare -g,它显式地使变量成为全局变量,这样就可以使用 (declare -ga)。 (由于关联数组 require declare -A 在 bash-4.2 之前,您将无法将此方法用于关联数组。)GNU parallel 文档对此方法有有用的变化,请参阅在man page 中讨论--env。
您的问题也表明您可能对export 本身有问题。您可以在创建或修改名称后导出它。 “可导出”是变量的标志或属性,为方便起见,您还可以在单个语句中设置和导出。最高 bash-4.2 export 只需要一个名称,支持简单(标量)变量或函数名称。
即使您可以(将来)导出数组,也可能不支持导出选定的索引(切片)(尽管由于数组是稀疏的,因此没有理由不允许这样做)。虽然 bash 也支持 declare -a name[0] 语法,但忽略了下标,“name”只是一个普通的索引数组。