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
循环,并使用适当的指示符传递您的参数。这需要更多的设计和更多的实现,但这是获得更多功能所需要的。
我希望能够做到:
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
循环,并使用适当的指示符传递您的参数。这需要更多的设计和更多的实现,但这是获得更多功能所需要的。