如何将导出的环境变量存储到文件/从文件加载导出的环境变量

如何将导出的环境变量存储到文件/从文件加载导出的环境变量

我希望能够将当前环境保存在文件中(用于运行交互式会话),以便我可以:

  • 保存,在运行会话中随意导出/修改/删除变量,然后恢复保存的环境
  • 多种环境随意切换
  • 检测两个环境之间的差异

我只对导出的变量感兴趣。因为我希望能够恢复环境,所以它必须是 shell 函数,所以我使用的是 bash。理想情况下,它不依赖于外部程序,并且可以在从 v3.2.25 到当前版本的 bash 版本上运行。

现在,为了保存我的环境,我使用以下函数:

env_save () {
    export -p > "$STORAGE/$1.sh"
}

env_save <filename>在跑步会话中使用它。我有一些样板代码来保存备份,但让我们忽略它。

但是,我在加载环境时遇到困难:

env_restore () {
    source "$STORAGE/$1.sh"
}

因为这不会删除我同时创建的虚假变量。也就是说,调用export -pafterenv_restore <filename>可能不会给出与 相同的输出cat $STORAGE/$1.sh

有没有一种干净的方法来处理这个问题?我可能需要将一些变量列入黑名单,例如 PWD、OLDPWD、SHELL、SLVL、USER、SSH_*、STORAGE 等...也就是说,这些变量不应保存,并且在恢复时不应更改,因为它们是特殊变量。我无法使用白名单,因为我不知道那里会有哪些变量。

答案1

POSIXly,你可以这样做:

# save
export -p > saved-env

...

# restore
blacklisted () {
  case $1 in
    PWD|OLDPWD|SHELL|STORAGE|-*) return 0 ;;
    *) return 1 ;;
  esac
}

eval '
  export() {
    blacklisted "${1%%=*}" || unset -v "${1%%=*}"
  }
  '"$(export -p)"
export() {
  blacklisted "${1%%=*}" || command export "$@"
}
. saved-env
unset -f export

请注意,对于bash未调用为 的情况sh,您需要发出 aset -o posix才能使其正常工作。此外,对于bash4.4 之前的版本,获取 的输出export -p可能是不安全的:

$ env -i 'a;reboot;=1' /bin/bash -o posix -c 'export -p'
export OLDPWD
export PWD="/"
export SHLVL="1"
export a;reboot;

ksh93也有类似的问题。yash没有那个特定的,但仍然存在以以下开头的变量名称问题-

$ env -i -- '-p=' yash -c 'export -p'
export '-p'=''
export OLDPWD
export PWD='/'

如果保存和恢复变量时不在同一区域设置,还要注意潜在的问题。

bash-4.3$ locale charmap
ISO-8859-15
bash-4.3$ export Stéphane=1
bash-4.3$ export -p > a
bash-4.3$ LC_ALL=en_GB.UTF-8 bash -c '. ./a'
./a: line 5: export: `Stéphane=1': not a valid identifier

答案2

我找到了一种方法compgen -A export来获取环境变量列表:

blacklisted () {
    case $1 in
        PWD|OLDPWD|SHELL|STORAGE) return 0 ;;
        *) return 1 ;;
    esac
}

env_save () { # Assume "$STORAGE/#1.sh" is empty
    local VAR
    for VAR in $(compgen -A export); do
        blacklisted $VAR || \
            echo "export $VAR='${!VAR}'" >> "$STORAGE/$1.sh"
    done
}

env_restore () {
    local VAR
    for VAR in $(compgen -A export); do
        blacklisted $VAR || \
            unset $VAR
    done
    source "$STORAGE/$1.sh"
}

相关内容