是的,这使得问题更加棘手。但并非不可能。
你无法直接导出一个数组。但是你可以使用declare -p
将数组转换为该数组的描述,并将该描述存储在可导出的变量中。事实上,你可以将该描述存储在函数中并导出该函数,尽管这有点像一个hack,并且你必须处理在函数内执行declare
命令会使声明的变量成为局部变量的事实,因此你需要在生成的declare
函数中引入-g
标志。
更新:自从Shellshock事件发生以来,上述hack方法已经无效了。这种主题的一种小变化确实有效。因此,如果你的bash已经更新,请跳到小标题“ShellShock版本”。
所以,这是一种可能的生成可导出函数的方式:
make_importer () {
local func=$1; shift;
export $func='() {
'"$(for arr in $@; do
declare -p $arr|sed '1s/declare -./&g/'
done)"'
}'
}
现在我们可以创建数组并为它们构建一个导入器和导出器。
$ declare -A ar='([one]="1" [two]="2" )'
$ declare -a ari='([0]="one" [1]="two")'
$ make_importer ar_importer ar ari
看看我们所构建的东西
$ echo "$ar_importer"
() {
declare -Ag ar='([one]="1" [two]="2" )'
declare -ag ari='([0]="one" [1]="two")'
}
好的,这个格式有点丑,但这不是关于空格的问题。然而,这里有一个技巧。我们那里只有一个普通的(虽然是导出的)变量,但当它被导入到子shell中时,会发生一些魔法[注1]:
$ bash -c 'echo "$ar_importer"'
$ bash -c 'type ar_importer'
ar_importer is a function
ar_importer ()
{
declare -Ag ar='([one]="1" [two]="2" )';
declare -ag ari='([0]="one" [1]="two")'
}
现在看起来更漂亮了。
现在我们可以在给parallel
的命令中运行它:
$ printf %s\\n ${!ari[@]} |
parallel \
'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2
或者,在远程机器上执行:
$ printf %s\\n ${!ari[@]} |
parallel -S localhost --env ar_importer \
'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2
ShellShock版本。
不幸的是,对shellshock的大量修复使得完成相同任务变得更加困难。特别地,现在需要将名为foo
的函数导出为环境变量BASH_FUNC_foo%%
,这是一个无效的名称(因为百分号)。但我们仍然可以定义该函数(使用eval
)并导出它,如下所示:
make_importer () {
local func=$1; shift;
eval "$func"'() {
'"$(for arr in $@; do
declare -p $arr|sed '1s/declare -./&g/'
done)"'
}'
export -f "$func"
}
如上所述,我们可以构建数组并制作导出器:
$ declare -A ar='([one]="1" [two]="2" )'
$ declare -a ari='([0]="one" [1]="two")'
$ make_importer ar_importer ar ari
但现在,在我们的环境中,这个函数实际上作为一个函数存在:
$ type ar_importer
ar_importer is a function
ar_importer ()
{
declare -Ag ar='([one]="1" [two]="2" )';
declare -ag ari='([0]="one" [1]="two")'
}
由于已经导出,我们可以在给parallel
的命令中运行它:
$ printf %s\\n ${!ari[@]} |
parallel \
'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2
不幸的是,它在远程机器上不再起作用(至少在我可以使用的 parallel
版本中),因为 parallel
不知道如何导出函数。如果这个问题得到解决,以下内容应该可以正常工作:
$ printf %s\\n ${!ari[@]} |
parallel -S localhost --env ar_importer \
'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
然而,有一个重要的警告:您不能将具有shellshock补丁的Bash中的函数导出到没有打补丁的Bash中,反之亦然。因此,即使`parallel`得到修复,远程机器必须运行与本地计算机相同的Bash版本。(或者至少,两者都必须有或都没有Shellshock补丁。)
注1:神奇的地方在于,`bash`将导出变量标记为函数的方式是导出值以`() {`开头。因此,如果您导出以这些字符开头并且是语法上正确的函数的变量,则`bash`子Shell将将其视为函数。(不过,请不要指望非`bash`子Shell会理解)