【问题标题】:Why is this Bash script not inheriting all environment variables?为什么这个 Bash 脚本没有继承所有环境变量?
【发布时间】:2018-12-18 17:20:17
【问题描述】:

我正在尝试一些非常简单的方法:

PEOPLE=(
  "nick"
  "bob"
)
export PEOPLE="$(IFS=, ; echo "${PEOPLE[*]}")"
echo "$PEOPLE"  # prints 'nick,bob'
./process-people.sh

由于某种原因,process-people.sh 没有看到 $PEOPLE。例如,如果我从 process-people.sh 内部 echo "$PEOPLE",它会打印一个空行。

据我了解,调用./process-people.sh创建的子进程应该继承父进程的所有环境变量,包括$PEOPLE。 然而,我在 Bash 3.2.57(1)-release 和 4.2.46(2)-release 上都试过了,但它不起作用。

这是怎么回事?

【问题讨论】:

    标签: bash


    【解决方案1】:

    对于joining the elements of a Bash array into a string,这是一个很好的解决方案。你知道在 Bash 你cannot export array variables to the environment 吗?而如果一个变量不在环境中,那么子进程将看不到它。

    啊。但是您不是在导出数组,是吗。您正在将数组转换为字符串,然后将其导出。所以它应该可以工作。

    但这是 Bash!各种历史事故合力让你指手画脚。

    正如@PesaThe 和@chepner 在下面的 cmets 中指出的那样,您实际上无法将 Bash 数组变量转换为字符串变量。根据Bash reference on arrays

    引用不带下标的数组变量等价于引用下标为 0。

    因此,当您调用 export PEOPLE=... 之前为 PEOPLE 分配了一个数组值时,您实际执行的是 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'
    

    不幸的是,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
    

    这里的关键是将数组和派生字符串分配给不同的变量。 由于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")'
    

    printenv 只会返回环境变量的值,而echo 将打印结果,无论变量是否已正确导出。

    declare -p 将显示变量的完整值,而不会出现与包含或省略数组索引引用相关的问题(例如 ARRAY_VARIABLE[*])。

    【讨论】:

    • Referencing an array variable without a subscript is equivalent to referencing with a subscript of 0. 所以PEOPLE=$(...) 所做的只是将命令替换的结果分配给PEOPLE[0]。所以没有转换,仍然是无法导出的数组:)
    • @PesaThe - 不确定你指的是什么。是否有我写的特定代码行不像我说的那样工作?
    • 啊,您是说将字符串分配给数组变量只是填充数组的 0 索引。正确的?所以即使我做export PEOPLE="some string",它只会覆盖PEOPLE数组的0索引?
    • @NickChammas 对;一旦设置了名称的数组属性,仅分配给名称将始终分配给数组的第 0 个元素。您不能取消设置数组属性(缺少取消设置名称本身)。
    • 您甚至可以看到将常规变量转换为数组所需的最小更改。 (这与问题没有严格的关系,但看到发生的事情很有趣,因为“乐趣”的一些极小的价值。)在x=3 之后,运行declare -p x 以查看它是一个常规变量。然后运行declare -a x,然后运行declare -p x。您会看到之前的 x 值现在是数组 x 的第 0 个元素的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 2019-04-21
    • 1970-01-01
    • 2019-12-08
    • 2015-02-03
    相关资源
    最近更新 更多