Como armazenar / carregar variáveis de ambiente exportadas para / de um arquivo

5

Eu gostaria de poder salvar meu ambiente atual em um arquivo (para uma sessão interativa em execução), para que eu possa:

  • Salve, exporte / modifique / exclua variáveis à vontade na sessão em execução e restaure o ambiente salvo
  • Alternar à vontade entre vários ambientes
  • Detectar diferenças entre dois ambientes

Estou interessado apenas em variáveis exportadas. Como eu quero ser capaz de restaurar o ambiente, tem que ser uma função de shell, estou usando o bash. Idealmente, não dependeria de programas externos e funcionaria em versões do bash da v3.2.25 para a atual.

Por enquanto, para salvar meu ambiente, uso a seguinte função:

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

Isso eu uso como env_save <filename> em uma sessão em execução. Eu tenho algum código clichê para manter backups, mas vamos ignorar isso.

No entanto, tenho dificuldades em carregar o ambiente de volta:

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

Como isso não removeria as variáveis falsas que eu criei no tempo médio. Ou seja, chamar export -p após env_restore <filename> talvez não forneça a mesma saída que cat $STORAGE/$1.sh .

Existe uma maneira limpa de lidar com esse problema? Eu provavelmente precisarei listar algumas variáveis como PWD, OLDPWD, SHELL, SHLVL, USER, SSH_ *, STORAGE, etc ... Ou seja, essas variáveis não devem ser salvas e não devem ser alteradas ao serem restauradas, pois são variáveis especiais . Não consigo usar uma lista de permissões, pois não sei quais variáveis estarão lá.

    
por Nonyme 07.09.2016 / 15:46

2 respostas

5

POSIXly, você pode fazer:

# 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

Observe que, para bash não chamado como sh , você precisará emitir set -o posix para que funcione corretamente. Também com bash versões anteriores a 4.4, o fornecimento da saída de export -p é potencialmente inseguro:

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

O ksh93 tem um problema semelhante. yash não tem aquele em particular, mas ainda tem problemas com nomes de variáveis que começam com - :

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

Tenha também cuidado com possíveis problemas se você não estiver na mesma localidade ao salvar e restaurar as variáveis.

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
    
por 07.09.2016 / 18:15
1

Eu encontrei um caminho usando compgen -A export para obter a lista de variáveis de ambiente:

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"
}
    
por 07.09.2016 / 16:33