安全保存和恢复环境变量

安全保存和恢复环境变量

我有一个脚本,可以解析基本.env文件并将其内容导出为环境变量,然后再采取进一步操作:

set -eu

test -f .env && load_dotenv

exec ./foobar x y z "$@"

但是,这会导致定义的环境变量.env优先于用户 shell 中定义的环境变量。我想要相反的行为:我希望在 shell 中显式设置的环境变量优先于文件中定义的任何内容.env

因此,我希望在运行之前“保存”当前环境load_dotenv,然后在运行后“重新应用”保存的环境load_dotenv

set -eu

user_env="$( env )"

test -f .env && load_dotenv

reapply_env "$user_env"  # ???

exec ./foobar x y z "$@"

我如何实现reapply_env,以便它可以处理任意环境变量?据我所知,除此之外的任何字节\0在环境变量中都是有效的,所以我想确保这适用于任何任意环境变量。例如,在环境变量中嵌入换行符有合法的(尽管不常见)用例。

我愿意接受特定于 shell 的答案,但假设我使用的是 Bourne 风格的 shell(Bash、Ksh、Zsh 等)。

忽略安全问题。假设我在受信任、受控的环境中操作,并且任何像“欺骗开发人员下载恶意.env文件”这样的场景都涉及更广泛的安全问题,超出了本问题的范围。

编辑:如何避免覆盖环境变量是一个很好的问题,但这不是我有兴趣回答这个特定问题的内容。如果还没有重复的内容,我可以为此单独发布一篇。

答案1

Bash 能够在设置环境变量之前对其进行测试。所以你可以.env这样写你的文件:

VAR1="default value"
VAR2=${VAR2:="default value"}

现在,如果您有一个新会话(批处理或终端)并执行以下操作:

$ source .env
$ echo $VAR1 - $VAR2
default value - default value
$ VAR1="my value"
$ VAR2="my value"
$ source .env
$ echo $VAR1 - $VAR2
default value - my value

该语法描述如下:https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion

ksh和都zsh具有相似的能力,对于“如果变量不存在则为该变量赋值”任务具有相同的语法:

https://www.ibm.com/docs/en/aix/7.1?topic=shell-parameter-substitution-in-korn-posix

https://zsh.sourceforge.io/Doc/Release/Expansion.html#Parameter-Expansion

答案2

在 Bash 中(不确定支持的最低版本),export内置函数会发出一个可以eval-ed 或source-d 的有效脚本:

#!/usr/bin/env bash

export FOO=$'a\nb'

export > ./user-env.bash

env -u FOO bash -c '
source ./user-env.bash ;
sh -c "printf \"%q\n\" \"$FOO\""
'

输出应为:

$'a\nb'

Zsh 也发出一个有效的脚本,但它确实不是包含任何export声明,而 Bash 版本包含declare -x在每行的开头。所以我仍在寻找 Zsh 解决方案。

答案3

如果你使用的是Linux,你可以阅读以下内容/proc/self/environ来保存环境变量:

myenv=()
while IFS= read -d '' -r var; do
  myenv+=("$var");
done < /proc/self/environ

然后,加载 env 文件后,使用该数组再次设置这些值(假设变量名称不包含=):

for i in "${myenv[@]}";
do
  export "$i";
done

相关内容