如何在不影响调用它的环境的情况下更改 bash 函数的环境?

How can I change the environment of my bash function without affecting the environment it was called from?

我正在编写一个 bash 脚本,该脚本需要对多个目录进行操作。在每个目录中,它需要为该目录​​提供一个唯一的安装脚本,然后 运行 一些命令。我需要在获取该脚本时设置环境以仅在函数内部持久存在,就好像它已作为外部脚本被调用,对调用脚本没有持久影响。

作为一个简化的例子,如果我有这个脚本,sourced.sh:

export foo=old

我把这个作为我的 driver.sh:

export foo=young
echo $foo
source_and_run(){ 
    source ./sourced.sh 
    echo $foo 
}
source_and_run
echo $foo

我想知道如何在驱动程序中更改 source_and_run 的调用以便打印:

young
old
young

我还需要能够从函数中收集 return 值。我很确定有一种简单的方法可以实现这一点,但到目前为止我还没有找到它。

正在创建另一个脚本 external.sh:

source ./sourced.sh; echo $foo

并定义 source_and_run 如

source_and_run(){ ./external.sh; return $? }

会起作用,但似乎没有必要管理额外的脚本层。

你说

Creating another script like external.sh:

source ./sourced.sh; echo $foo

and defining source_and_run like

source_and_run(){ ./external.sh; return $? }

would work but managing that extra layer of scripts seems like it shouldn't be necessary.

您可以通过使用子 shell 获得相同的行为。注意 () 而不是 {}.

但请注意,return $? 在您的情况下不是必需的。默认情况下,函数 returns 是其最后一个命令的退出状态。在您的例子中,该命令是 echo。因此,return 值将始终为 0

source_and_run() (
    source ./sourced.sh
    echo "$foo"
)

顺便说一句:更好的解决方案是重写 sourced.sh,使其打印 $foo。这样您就可以直接调用脚本,而不必获取它然后使用 echo $foo.

bash函数的真正目的是它与调用程序在同一进程中运行。

由于环境是可访问的(例如,使用命令printenv),您可以在函数的入口处保存环境并在最后恢复它。然而,更简单和更自然的方法是根本不使用函数,而是将其作为一个单独的 shell 脚本,在自己的进程中执行,因此有自己的环境,这不会影响不再来电了。