【问题标题】:Is there in bash an array_combine function, where I can create an associative array from two?bash 中是否有一个 array_combine 函数,我可以在其中从两个创建一个关联数组?
【发布时间】:2015-01-26 16:27:24
【问题描述】:

我有两个数组,一个是用户名,另一个是全名,它们实际上是由 wbinfo -u 动态生成的。

USR=(user1 user2 user3)
FULL=("full user 1" "full user 2" "full user 3")

我想创建一个关联数组,我可以将它与 pdbedit 一起使用,因此在循环中我将创建/修改用户名和全名(在 PHP 中使用 array_combine 很容易) .

pdbedit -u $username -f $fullname

【问题讨论】:

  • 仅供参考,全大写名称保留用于环境变量和 shell 内置函数;遵守此约定可防止命名空间冲突。
  • 感谢您的提醒。

标签: arrays linux bash samba


【解决方案1】:

您可以仅使用 bash 4.3 内置函数 (and no eval) 自行实现,如下所示:

combine() {
  declare key_no key val
  declare -n _keys=$1 _vals=$2 _dest=$3
  declare -g -A "$3"
  for key_no in "${!_keys[@]}"; do
    key=${_keys[$key_no]}
    val=${_vals[$key_no]}
    _dest[$key]=$val
  done
}

usr=(user1 user2 user3)
full=("full user 1" "full user 2" "full user 3")

combine usr full arr

这个版本需要一些额外的偏执才能正确处理稀疏数组。


如果您需要支持 4.3 之前的 bash 版本(理想情况下是 4.3 系列后期,因为存在影响 namevar 支持的安全漏洞,这可能导致 4.3 早期版本中的任意代码执行),那么以下代码使用declare 更谨慎一些(感谢Glenn Jackman 提出了这个解决方案,而不是这里以前的方法,它小心地使用了eval):

combine() {
  declare keys_var=$1 vals_var=$2 result_var=$3
  declare indirect i keys
  declare -gA "$result_var"

  indirect="${keys_var}[@]"; keys=( "${!indirect}" )
  for (( i=0; i < ${#keys[@]}; i++ )); do
    indirect="${vals_var}[$i]"; declare -g "${result_var}[${keys[i]}]=${!indirect}"
  done
}

【讨论】:

  • 谢谢。第二种方法对我有用,因为我的 bash 版本在一台机器上是 4.2.37,在另一台机器上是 4.3.30。
  • 很高兴这有帮助!顺便说一句,我又看了一眼,意识到我在声明局部变量方面有点草率;这两个版本现在应该会更好(不再将keyval 泄漏到全局范围内)。
  • ...第二个版本使用@glenn-jackman 建议的更好的方法再次更新。
  • 它工作正常,但是,当我运行 for 循环时,每个数组的所有项目都作为一个项目。因此,usr 中的所有名称都被视为一个名称,full 也是如此。我猜这是因为引号,但即使使用 awk 用引号括起来,结果也是一样的。
  • 如果您使用declare -p usrdeclare -p full,是否将它们显示为包含多个不同项目的数组?如果没有,我建议提出一个新问题,重点是您如何填充这些数组,并提供足够的详细信息来重现该问题。随意在这里放一个链接;我很想知道这个问题!
【解决方案2】:

没有现成的array combine例程,但你可以这样作弊:

USR=(user1 user2 user3)
FULL=("full user 1" "full user 2" "full user 3")

declare -A arr
eval "$(paste -d= <(printf 'arr[%q]\n' "${USR[@]}") <(printf '%q\n' "${FULL[@]}"))

测试一下:

declare -p arr
declare -A arr='([user3]="full user 3" [user2]="full user 2" [user1]="full user 1" )'

【讨论】:

  • 对于包含文字 $() 等的内容是否安全?
  • @CharlesDuffy 不,这根本不安全。可以用eval "$(paste -d= &lt;(printf 'arr[%q]\n' "${USR[@]}") &lt;(printf '%q\n' "${FULL[@]}")) 修复。
  • @gniourf_gniourf:非常感谢,我明白你的重点了。我应该使用%q 而不是%s,并在eval 中使用引号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
相关资源
最近更新 更多