访问关联数组在GNU并行 [英] Accessing Associative Arrays in GNU Parallel

查看:161
本文介绍了访问关联数组在GNU并行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设在猛砸以下内容:

declare -A ar='([one]="1" [two]="2" )'
declare -a ari='([0]="one" [1]="two")'
for i in ${!ari[@]}; do 
  echo $i ${ari[i]} ${ar[${ari[i]}]}
done
0 one 1
1 two 2

能否同样可以用GNU并行完成,并确保使用的关联数组,而不是序列的指数?难道事实阵列不能出口使这个困难,如果不是不可能的?

Can the same be done with GNU Parallel, making sure to use the index of the associative array, not the sequence? Does the fact that arrays can't be exported make this difficult, if not impossible?

推荐答案

是的,这使得它棘手。但并非不可能。

Yes, it makes it trickier. But not impossible.

您不能导出一个数组的直接的。但是,你可以把一个数组使用同一阵列的描述声明-p ,并且可以存储描述可导出的变量。事实上,你可以存储描述功能和导出功能,虽然它是一个黑客位,而你不得不面对一个事实,即执行声明命令在函数内部,使声明的变量的地方,所以你需要
引入 -g 标记到生成的声明功能。

You can't export an array directly. However, you can turn an array into a description of that same array using declare -p, and you can store that description in an exportable variable. In fact, you can store that description in a function and export the function, although it's a bit of a hack, and you have to deal with the fact that executing a declare command inside a function makes the declared variables local, so you need to introduce a -g flag into the generated declare functions.

更新:既然shellshock,上述黑客不起作用。关于为主题的微小变化确实工作。所以,如果你的bash已更新,请跳过了副标题ShellShock版本。

UPDATE: Since shellshock, the above hack doesn't work. A small variation on the theme does work. So if your bash has been updated, please skip down to the subtitle "ShellShock Version".

所以,这里的生成导出函数的一种可能的方式:

So, here's one possible way of generating the exportable function:

make_importer () {
  local func=$1; shift; 
  export $func='() {
    '"$(for arr in $@; do
          declare -p $arr|sed '1s/declare -./&g/'
        done)"'
  }'
}

现在我们可以创建数组和建设导出的进口商为他们:

Now we can create our arrays and build an exported importer for them:

$ declare -A ar='([one]="1" [two]="2" )'
$ declare -a ari='([0]="one" [1]="two")'
$ make_importer ar_importer ar ari

,看看我们已经建立

And see what we've built

$ echo "$ar_importer"
() {
    declare -Ag ar='([one]="1" [two]="2" )'
declare -ag ari='([0]="one" [1]="two")'
  }

确定,格式是有点难看,但是这不是空白。这里的黑客,但。而我们有的只是有一个普通的(尽管出口)可变的,但是当它被导入到一​​个子shell,有点奇迹发生[注1]:

OK, the formatting is a bit ugly, but this isn't about whitespace. Here's the hack, though. All we've got there is an ordinary (albeit exported) variable, but when it gets imported into a subshell, a bit of magic happens [Note 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")'
}

和它看起来prettier了。
现在,我们可以在我们给并行的命令来运行它

And it looks prettier, too. Now we can run it in the command we give to parallel:

$ printf %s\\n ${!ari[@]} |
    parallel \
      'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2

或者,在远程机器上执行:

Or, for execution on a remote machine:

$ printf %s\\n ${!ari[@]} |
    parallel -S localhost --env ar_importer \
      'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2


ShellShock版本

不幸的是修复的乱舞shellshock使其更难一点来完成相同的任务。特别是,它现在必须导出函数名为为名为环境变量 BASH_FUNC_foo %% ,这是一个无效的名称(因为百分号)。但是,我们仍然可以定义函数(使用评估),并将其导出,如下所示:


ShellShock version.

Unfortunately the flurry of fixes to shellshock make it a little harder to accomplish the same task. In particular, it is now necessary to export a function named foo as the environment variable named BASH_FUNC_foo%%, which is an invalid name (because of the percent signs). But we can still define the function (using eval) and export it, as follows:

make_importer () {
  local func=$1; shift; 
  # An alternative to eval is:
  #    . /dev/stdin <<< ...
  # but that is neither less nor more dangerous than eval.
  eval "$func"'() {
    '"$(for arr in $@; do
          declare -p $arr|sed '1s/declare -./&g/'
        done)"'
  }'
  export -f "$func"
}

如上,我们就可以建立阵列,使出口商:

As above, we can then build the arrays and make an exporter:

$ declare -A ar='([one]="1" [two]="2" )'
$ declare -a ari='([0]="one" [1]="two")'
$ make_importer ar_importer ar ari

但现在,函数实际上存在于我们作为一个函数环境:

But now, the function actually exists in our environment as a function:

$ type ar_importer
ar_importer is a function
ar_importer () 
{ 
    declare -Ag ar='([one]="1" [two]="2" )';
    declare -ag ari='([0]="one" [1]="two")'
}

既然已经出口,我们可以在我们给出的命令来运行它平行

$ printf %s\\n ${!ari[@]} |
    parallel \
      'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'
0 one 1
1 two 2

不幸的是,它不再工作在远程计算机上(至少平行我有可用的版本),因为平行不知道如何导出功能。如果这被固定,下面应该工作:

Unfortunately, it no longer works on a remote machine (at least with the version of parallel I have available) because parallel doesn't know how to export functions. If this gets fixed, the following should work:

$ printf %s\\n ${!ari[@]} |
    parallel -S localhost --env ar_importer \
      'ar_importer; echo "{}" "${ari[{}]}" "${ar[${ari[{}]}]}"'

然而,一条重要的:你不能从与shellshock补丁一个bash一个bash导出功能,无需修补,反之亦然。所以,即使平行被固定,在远程机器(S)必须运行同一版本的bash在本地机器。 (或者至少,要么都有,或者都必须有shellshock补丁。)

However, there is one important caveat: you cannot export a function from a bash with the shellshock patch to a bash without the patch, or vice versa. So even if parallel gets fixed, the remote machine(s) must be running the same bash version as the local machine. (Or at least, either both or neither must have the shellshock patches.)

注1 :神奇的是,作为一个功能是,出口值与准确的启动方式庆典标志着一个出口变量(){。所以,如果你导出的那些字符开头,是一个语法正确的函数的变量,那么庆典子shell将会把它作为一个功能。 (不要指望非 - 庆典子shell明白,虽然)

Note 1: The magic is that the way bash marks an exported variable as a function is that the exported value starts exactly with () {. So if you export a variable which starts with those characters and is a syntactically correct function, then bash subshells will treat it as a function. (Don't expect non-bash subshells to understand, though.)

这篇关于访问关联数组在GNU并行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆