首页 > 解决方案 > 将命名数组传递给另一个 bash 脚本

问题描述

我想将多个命名数组按原样传递给另一个 bash 脚本。例如,给定 external.sh

echo "outer"
a=(1 2)
b=(3 4 5)
echo ${#a[@]}
echo ${#b[@]}
a=${a[@]} b=${b[@]} sh inner.sh

和inner.sh

echo "inner"
echo ${a[@]}
echo ${b[@]}
echo ${#a[@]}
echo ${#b[@]}

运行 external.sh 给出

$ sh outer.sh
outer
2
3
inner
1 2
3 4 5
1
1

也就是说,即使保留了值,但它们的长度会发生变化,这意味着它们不再是数组,而是字符串。

如何按原样将多个命名数组传递给另一个 bash 脚本?

标签: arraysbashshell

解决方案


有几种方法可用,每种方法都有自己的缺点。


简单的方法:在子shell中运行内部脚本

这意味着所有变量都是继承的,包括那些不能通过环境传递的变量(比如数组!)。

a=(1 2)
b=(3 4 5)
(. inner)

当然,这也意味着 shell 设置(IFS,set -e等)也是继承的,因此inner.sh需要健壮地编写以处理它可能碰巧接收到的任何设置;并且您以后不能用其他/非shell语言重写它。


不安全的方式:通过eval-able 代码(并相信你的调用者!)

修改inner.sh为 run [[ $setup ]] && eval "$setup",然后调用它:

setup=$(declare -p a b) ./inner

显然,如果您不控制流程环境,这是一个严重的安全风险。


艰难的道路:反序列化为单个元素

在这里,我们将每个数组作为其名称、长度和原始元素传递。

inner需要修改以将其命令参数列表中的项目复制回数组中,如下例所示:

while (( $# )); do               # iterating over our argument list:
  dest_name=$1; shift            # expect the variable name first
  dest_size=$1; shift            # then its size
  declare -g -a "$dest_name=( )" # initialize our received variable as empty
  declare -n dest="$dest_name"   # bash 4.3: make "dest" point to our target name
  while (( dest_size )) && (( $# )); do  # and then, for up to "size" arguments...
    dest+=( "$1" ); shift                # pop an argument off the list onto an array
    (( dest_size -= 1 ))                 # and decrease the count left in "size"
  done
  unset -n dest   # end that redirection created above
done

...然后扩展到该格式outer

./inner a "${#a[@]}" "${a[@]}" b "${#b[@]}" "${b[@]}"

推荐阅读