语境:
- 操作系统: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 -e
shebang 无效,它被视为评论。如果您要将脚本更改为
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
中没有调用环境变量一样)。env
grep
您可以将 的值TEST_VAR
作为环境变量导入到脚本中,方法是使用 导出现有的 shell 变量export TEST_VAR
,或者像这样启动脚本
TEST_VAR=$TEST_VAR ./test.sh
或者
env TEST_VAR="$TEST_VAR" ./test.sh