bash:将关联数组作为参数传递给另一个脚本

bash: pass associative array as a parameter to another script

我希望能够做到:

Script1.sh

declare -A map=(
  ['A']=1
  ['B']=2
  ['C']=3
  ['D']=4
)

sh script2.sh ???

Script2.sh

params = ...
echo ${params['A']}

即按键访问参数。我看过普通数组的相关问题,答案是将数组传递为:

sh script2.sh "${AR[@]}"

我相信翻译成:

sh script2.sh  "${map[0]}" "${map[1]}" "${map[2]}"

但是这样一来,我只能根据顺序访问元素。

有什么巧妙的技巧可以达到我想要的效果吗?也许是传递给 "A=1" "B=2" "C=3" "D=4" 并让 script2.sh 解析它们的东西?或者有更好的解决方案吗?

假设:

  • 数组是唯一传递给 script2 的项目(这可以放宽但可能需要向 script2 添加一些选项标志处理)
  • 数组名称将始终为 map(可能会使其动态化,但那是另一天的事)
  • 数组索引和值不包含任何 special/control 字符(例如换行符),否则在命令行上将数组结构传递给 script2 会很快变得非常复杂(可能有这种情况也有一些解决方法)

一些基本组件:

名为map的数组:

$ declare -A map=(
  ['A']=1
  ['B']=2
  ['C']=3
  ['D']=4
)

使用typeset生成命令来(重新)生成数组map的内容:

$ typeset -p map
declare -A map=([A]="1" [B]="2" [C]="3" [D]="4" )

从这里我们可以将 typeset 输出传递给 script2,然后让 script2 eval 对输入进行运算,例如:

$ cat script1
echo "in script1"
declare -A map=(
  ['A']=1
  ['B']=2
  ['C']=3
  ['D']=4
)
./script2 $(typeset -p map)

$ cat script2
echo "in script2"
echo " $@ = $@"
eval "$@"
for i in "${!map[@]}"
do
        echo "${i} : ${map[${i}]}"
done

运行 script1 生成:

$ ./script1
in script1
in script2
 $@ = declare -A map=([A]="1" [B]="2" [C]="3" [D]="4" )
A : 1
B : 2
C : 3
D : 4

我知道,我知道,我知道... eval ==邪恶。我将不得不考虑 eval 的替代品......也愿意接受建议。

如果您script1.sh内部调用script2.sh,那么您需要做的就是(正如@markp-fuso所指出的)是源 script2.sh,它将在当前上下文中 运行 加载所有数据。

如果您真的希望它出现在命令行中,则将其作为 key=val 传递并让您的代码在 script2.sh 中检查该格式的每个参数并将它们设置为关联数组。

declare -A map=()
for arg in "$@"
do if [[ "$arg" =~ ^[A-Z]=[0-9]$ ]] # more complex k/v will get ugly
   then map[${arg/=?}]=${arg/?=}    # as will the assignment w/o eval
   fi
done
# And finally, just to see what got loaded -
declare -p map

$: script2.sh C=3 A=1
declare -A map=([A]="1" [C]="3" )

如上所述,一组更复杂的键名 and/or 值可能需要更复杂的测试和赋值逻辑。显然,除了最简单的情况,这很快就会出现问题。

更好的是,设置一个完整的 getopts 循环,并使用适当的指示符传递您的参数。这需要更多的设计和更多的实现,但这是获得更多功能所需要的。