将数组值存储在环境变量中然后从 Bash 脚本调用的解决方法

将数组值存储在环境变量中然后从 Bash 脚本调用的解决方法

我四处寻找“我可以使用数组作为环境变量,然后从 Bash shell 脚本调用它”这个问题的答案,并得出结论,它没有得到“官方”支持(概述)这里, 和这里)。

然而,我确实需要这样做,并想出了一个“解决方法”,并希望得到您的意见。

设置:我在文件中创建了一个变量.profile,如下所示:

HOST_NAMES='server1 server2 server3'

然后在 shell 脚本的开头我写道:

SRVR_ARRAY=($(echo $HOST_NAMES | awk '{for (i = 1; i <=NF; i++) print $i " "}'))

后来在脚本中,当需要做一些工作时,我调用了:

for h in "${SRVR_ARRAY[@]}"; do
ping $h
done

它成功了!现在我确信这是 Bash shell 脚本 jerry-riggin 最好的版本,但想看看是否有人能看到这种用法的任何风险?

答案1

您可能面临的问题是常见的:分裂和通配符。

字符串中不能包含空格,因为它们将被拆分为单独的数组项,并且任何类似于全局字符 ( *?[]) 的内容都将扩展为匹配的文件名。虽然主机名可能不是问题,但总的来说,确实如此。

这是一个常见问题,反复讨论,参见例如 shell 变量的扩展以及 glob 和 split 对它的影响忘记在 bash/POSIX shell 中引用变量的安全隐患


要解决这些问题,您需要 a) 设置IFS为空格以外的其他内容,并用它分隔字符串,b) 禁用set -f.

这将用作|分隔符并分割字符串。您可以使用值中不需要的任何字符,甚至可能是一些控制字符,例如\001$'\001'在 Bash 中使用来创建它)。

#!/bin/bash
string='foo|bar'
IFS='|'; set -f
array=($string)        # split it

IFS='|'
string="${array[*]}"   # merge it back together

另外,就像他们在评论中所说的那样,如果您的变量只有主机名并且您可以在空格上拆分,则不需要 awk 来拆分它。 shell 将在分配给数组或启动循环时执行此操作:

SRVR_ARRAY=( $HOST_NAMES )
for x in $HOST_NAMES ; do ...

HOST_NAMES(同样,如果包含全局字符,您会遇到麻烦。)

实际上,即使在您的示例中也会发生这种情况:awk打印一些内容,shell 捕获它,将其拆分为单词,因为$()不在双引号内,然后将单词单独保存在数组中。

答案2

您可以将输出存储declare -p在环境变量中:

array=(foo 'bar baz'); array[12]=sparse
export ARRAY_definition="$(declare -p array)"

然后,在执行的bash脚本中:

eval "$ARRAY_definition"

请注意,重要的是要eval在与 相同的语言环境中执行declare(最好是相同的版本bash

如果eval不在全局范围内运行,则将声明该数组当地的

使用zsh,您可以使用引用来避免使用危险的eval

export ARRAY_definition=${(j: :)${(q)array}}

导入:

array=(${(Q)${(z)ARRAY_definition}})

rc或者,您可以使用类似,esfish支持本机导出数组(使用它们自己的编码)的shell 。

相关内容