连续使用源之间持久环境变量背后的基本原理

连续使用源之间持久环境变量背后的基本原理

语境:

  • 操作系统:openSUSE Leap 15.1
  • 核心:Linux 4.12.14-lp151.27-默认
  • 壳:GNU bash,版本 4.4.23(1)-发布 (x86_64-suse-linux-gnu)

给定以下脚本,我们将其称为 test.sh:

#!/bin/bash -e
echo "$TEST_VAR"

在不同的运行中,它返回:

TEST_VAR=1234; source test.sh->输出1234

source test.sh -> 输出1234

问题:

  • 为什么env的值测试变量在运行之间持续存在(env | grep -i test_var)也不返回任何内容)?
  • 有什么方法可以防止这种情况而不是使用类似的东西exec bash
  • 如果前面的答案是肯定的,是否有任何解决方案至少在某种程度上是跨 shell 的?

谢谢。

答案1

source(同义词.(点)将要

在当前环境下执行命令

也就是说,它不会test.sh在具有自己的变量的新 shell 中执行,而只是在当前 shell 中运行其中的每个命令。特别是,这会使您的#!/bin/bash -eshebang 无效,它被视为评论。如果您要将脚本更改为

set -e
echo "$TEST_VAR"
false

source由于返回码为 ,它将立即退出交互式会话false。如果您没有将当前 shell 的输出保存在某处,则任何错误消息都将因此丢失(这对于 just 来说并不那么重要false,但对于真正的脚本来说很重要)。我建议不要source结合使用来set -e运行任何可能失败的脚本。

TEST_VAR=1234; source test.sh保留 的值,TEST_VAR因为;简单地分隔命令,使得TEST_VAR=1234; source test.sh

TEST_VAR=1234
source test.sh

这只是对 的赋值,TEST_VAR然后是对 的调用source。由于source在当前环境中运行命令,TEST_VAR因此在该环境中可用。

如果;不存在,则可以通过使分配TEST_VAR仅对命令的调用有效来改变source

$ cat test.sh
#!/bin/bash -e
echo $TEST_VAR
$ TEST_VAR=1234 source test.sh
1234
$ source test.sh

env | grep -i test_var也不返回任何内容

其原因解释于https://unix.stackexchange.com/a/268258/4699:

env 是一个外部命令(与 shell 内置命令相反),因此,env 只打印从 shell 导出的变量。

另一侧的 set 列出了所有 shell 变量。其中一些是出口的。

export 列出了 shell 导出的 shell 变量。

export也可用于导出已设置的变量:

$ TEST_VAR=1234; source test.sh
1234
$ set | grep TEST
TEST_VAR=1234
$ env | grep TEST
$ export TEST_VAR
$ env | grep TEST
TEST_VAR=1234

答案2

在脚本上使用source.将在当前 shell 环境中运行它。

这意味着当前 shell 中可用的任何 shell 变量也将在点脚本(正在获取的脚本)中可用。这也意味着#!脚本的 - 行将被完全忽略。

您显示的命令将变量 设定TEST_VAR为某个值。然后你获取点脚本,它将可以访问该 shell 变量,因为它是获取的,所以它会打印它的值。

然后您再次获取相同的点脚本。由于unset自上次获取脚本以来shell 变量尚未显式显示,因此会再次打印该值。

env您从+管道中没有得到任何输出,grep因为您没有环境与该模式匹配的变量。请注意,它TEST_VAR永远不会导出到环境中,它严格来说是一个 shell 变量,因此不会被子进程继承(例如env)。

如果您将脚本作为普通脚本运行,即通过使用 使其可执行chmod +x test.sh,然后执行./test.sh,您会注意到TEST_VAR脚本中变量的值为空。这是因为脚本无法访问调用 shell 的 shell 变量,并且当前环境中没有调用环境变量(就像+管道TEST_VAR中没有调用环境变量一样)。envgrep

您可以将 的值TEST_VAR作为环境变量导入到脚本中,方法是使用 导出现有的 shell 变量export TEST_VAR,或者像这样启动脚本

TEST_VAR=$TEST_VAR ./test.sh

或者

env TEST_VAR="$TEST_VAR" ./test.sh

相关内容