【问题标题】:bash: pass associative array as a parameter to another scriptbash:将关联数组作为参数传递给另一个脚本
【发布时间】:2023-04-03 15:58:01
【问题描述】:

我希望能够做到:

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 解析它们?还是有更简洁的解决方案?

【问题讨论】:

  • 你以前查过类似的问题吗 - 一个简单的搜索提供了我 1.How to pass an associative array as argument to a function in Bash? 2.Passing associative array as argument with Bash
  • 请注意sh 没有数组。
  • params = ... 是无效语法或shbash。您是否在shellcheck.net 检查过您的代码?您是否有理由不在每个脚本的顶部使用“shebang”行来控制 shell 解释您的代码(即#!/bin/bash),而不是您当前的代码bash script2?如果读者编辑您的 Q,那么就有可能做出无助于定义您的问题的更改。明确定义你的问题是你的责任,对吧?祝你好运。
  • 我们随时为您提供帮助,但明确定义您的问题是您的责任。要有耐心并学习使用该网站的最佳方式(请参阅this guide 了解更多信息),但如果您是寻求帮助的人,则不能指望其他人负责猜测您想要什么。坚持下去。尽自己的一份力量,您将拥有数千年的用户经验来指导您。粗心和/或防御只会让他们转向一个更有趣的问题来解决。请记住,我们不会为此获得报酬。帮助我们帮助您。
  • 它有淡淡的XY Problem的味道。

标签: bash associative-array


【解决方案1】:

如果您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" )

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

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

【讨论】:

  • 取决于script2 中的其他内容,也可以只获取script2(没有命令行参数)
  • 你不能导出数组,反正没用。
  • [增加 OPs 收益] re: sourcing script2 ... (显然)需要确保在 script2 中没有 exit 调用,否则 exit 将在 @987654335 中调用@ 从而导致 script1 在执行任何其他处理之前终止
【解决方案2】:

假设:

  • 数组是唯一传递给script2的项目(这可以放宽,但可能需要向script2添加一些选项标志处理)
  • 数组名称将始终为 map(可能会使其动态化,但那是另一天的事了)
  • 数组索引和值不包含任何特殊/控制字符(例如,换行符),否则将命令行上的数组结构传递给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 evaluate 输入,例如:

$ 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 ... 也欢迎提出建议。

【讨论】:

  • 我更喜欢将typeset/declare 的输出写入一个单独的文件并获取它。有优点也有缺点。不过,这应该很好用。
  • 是的,我认为 (typeset -p > 文件;将文件提供给 script2) 作为扩展答案(尤其是)如果数组索引或值包含特殊/控制字符;有几种方法可以将这个切片...
  • 如果你把./script2 "$(typeset -p map)"这样的双引号,我认为evalsource是完全等价的。你能看出有什么不同吗?
猜你喜欢
  • 2017-09-26
  • 1970-01-01
  • 1970-01-01
  • 2013-07-07
  • 2011-11-01
  • 2022-12-08
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
相关资源
最近更新 更多