我正在尝试一些非常简单的事情:
PEOPLE=(
"nick"
"bob"
)
export PEOPLE="$(IFS=, ; echo "${PEOPLE[*]}")"
echo "$PEOPLE" # prints 'nick,bob'
./process-people.sh
Run Code Online (Sandbox Code Playgroud)
出于某种原因,process-people.sh没有看到$PEOPLE. 就像,如果 I echo "$PEOPLE"from inside process-people.sh,它会打印一个空行。
据我了解,通过调用创建的子进程./process-people.sh应该继承父进程的所有环境变量,包括$PEOPLE. 然而,我在 Bash 3.2.57(1)-release 和 4.2.46(2)-release 上都试过这个,但它不起作用。
这里发生了什么?
这是将 Bash 数组的元素连接到 string的巧妙解决方案。您知道在 Bash中不能将数组变量导出到环境吗?如果变量不在环境中,那么子进程将看不到它。
啊。但是您不是在导出数组,是吗。您正在将数组转换为字符串,然后将其导出。所以它应该工作。
但这是 Bash!历史的各种事故合谋给你一个手指。
正如@PesaThe 和@chepner 在下面的评论中指出的那样,您实际上无法将 Bash 数组变量转换为字符串变量。根据数组上的Bash 参考:
引用一个没有下标的数组变量相当于引用一个下标为 0 的变量。
因此,当您调用先前分配给数组值的export PEOPLE=...wherePEOPLE时,您实际上在做的是PEOPLE[0]=.... 这是一个更完整的例子:
PEOPLE=(
"nick"
"bob"
)
export PEOPLE="super"
echo "$PEOPLE" # masks the fact that PEOPLE is still an array and just prints 'super'
echo "${PEOPLE[*]}" # prints 'super bob'
Run Code Online (Sandbox Code Playgroud)
不幸的是,export默默地未能将数组导出到环境(它返回0),并且在某些情况下Bash 等同ARRAY_VARIABLE于令人困惑ARRAY_VARIABLE[0]。我们只需要将其归结为历史和向后兼容性的组合。
这是您的问题的有效解决方案:
PEOPLE_ARRAY=(
"nick"
"bob"
)
export PEOPLE="$(IFS=, ; echo "${PEOPLE_ARRAY[*]}")"
echo "$PEOPLE" # prints 'nick,bob'
./process-people.sh
Run Code Online (Sandbox Code Playgroud)
这里的关键是将数组和派生字符串分配给不同的变量。由于PEOPLE是一个合适的字符串变量,它可以很好地导出process-people.sh并按预期工作。
无法将 Bash 数组变量直接更改为字符串变量。一旦一个变量被赋予一个数组值,它就成为一个数组变量。将它改回字符串变量的唯一方法是销毁它unset并重新创建它。
Bash 有几个方便的命令用于检查对调查此类问题有用的变量:
printenv PEOPLE # prints 'nick,bob'
declare -p PEOPLE_ARRAY # prints: declare -ax PEOPLE_ARRAY='([0]="nick" [1]="bob")'
Run Code Online (Sandbox Code Playgroud)
printenv只会返回环境变量的值 vs. echo,无论变量是否已正确导出,它都会打印结果。
declare -p将显示变量的完整值,没有与包含或遗漏数组索引引用(例如ARRAY_VARIABLE[*])相关的问题。