Definir variáveis ​​de ambiente do arquivo de pares chave / valor


514

TL; DR: Como exportar um conjunto de pares de chave / valor de um arquivo de texto para o ambiente do shell?


Para o registro, abaixo está a versão original da pergunta, com exemplos.

Estou escrevendo um script no bash que analisa arquivos com 3 variáveis ​​em uma determinada pasta, este é um deles:

MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"

Este arquivo é armazenado em ./conf/prac1

Meu script minientrega.sh analisa o arquivo usando este código:

cat ./conf/$1 | while read line; do
    export $line
done

Mas quando executo minientrega.sh prac1na linha de comando, não define as variáveis ​​de ambiente

Eu também tentei usar, source ./conf/$1mas o mesmo problema ainda se aplica

Talvez exista alguma outra maneira de fazer isso, eu só preciso usar as variáveis ​​de ambiente do arquivo que passo como argumento do meu script.




Essa é uma ótima pergunta, mas é formulada de maneira muito específica, com nomes de variáveis ​​específicos ("MINIENTREGA_FECHALIMITE"? O que isso significa?) E números (3). A questão geral é simplesmente "Como exportar um conjunto de pares de chave / valor de um arquivo de texto para o ambiente do shell".
Dan Dascalescu

Além disso, isso já foi respondido no unix.SE e, sem dúvida, é mais sobre o assunto.
Dan Dascalescu

Respostas:


209

Problema com a sua abordagem é a exportdo whilelaço está acontecendo em um sub shell, e aqueles variável não estará disponível no shell atual (shell pai de while loop).

Adicionar exportcomando no próprio arquivo:

export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"

Em seguida, você precisa obter o arquivo no shell atual usando:

. ./conf/prac1

OU

source ./conf/prac1

4
Embora a leitura da linha por linha do arquivo e passando cada linha para exportnão é o ideal, o problema também pode ser corrigido simplesmente usando redirecionamento de entrada no loop: while read line; do ... ; done < ./conf/$1.
chepner

4
E se não for de um arquivo, use< <(commands that generate output)
o11c 31/08/17

5
Você tem uma solução mais limpa , eu tenho uma preferência porset -o allexport
heralight 28/10

2
Se usar esse arquivo .env entre sistemas, inserção exportiria quebrá-lo para coisas como Java, Systemd, ou outras ferramentas
FilBot3

1
awk '{print "export " $0}' envfilecomando de conveniência para
incluir previamente

888

Isso pode ser útil:

export $(cat .env | xargs) && rails c

A razão pela qual eu uso isso é se eu quero testar .envcoisas no meu console de rails.

O gabrielf criou uma boa maneira de manter as variáveis ​​locais. Isso resolve o problema potencial ao passar de um projeto para outro.

env $(cat .env | xargs) rails

Eu testei isso com bash 3.2.51(1)-release


Atualizar:

Para ignorar as linhas que começam com #, use isto (graças ao comentário de Pete ):

export $(grep -v '^#' .env | xargs)

E se você quiser unsettodas as variáveis ​​definidas no arquivo, use o seguinte:

unset $(grep -v '^#' .env | sed -E 's/(.*)=.*/\1/' | xargs)

Atualizar:

Para também manipular valores com espaços, use:

export $(grep -v '^#' .env | xargs -d '\n')

em sistemas GNU - ou:

export $(grep -v '^#' .env | xargs -0)

em sistemas BSD.


6
Obrigado, eu gosto que isso não exija anexar nada ao arquivo - permite compatibilidade com o formato Foreman (Procfile) .env.
Natevw

29
Eu vim com a solução: env $ (cat .env | xargs) rails
gabrielf

4
Isso parece não funcionar se algum dos valores env tiver espaços, embora eu não esteja realmente certo de qual é a melhor / desejada maneira de especificar valores com espaços. O github.com/ddollar/foreman/issues/56 diz que deve funcionar assim, export $(cat .env)mas não sei como lidar com os espaços.
precisa saber é o seguinte

6
@BenjaminWheeler GNU linux tem -dpara definir o delimitador, por isso estou tentando env $(cat .env | xargs -d '\n') rails, mas ainda assim erros com um arquivo não encontrado se .envtiver espaços. Alguma idéia de por que isso não funciona?
Bailey Parker

19
Aqui está uma variação menoreval $(cat .env) rails
Manalang

413

-o allexportpermite que todas as seguintes definições de variáveis ​​sejam exportadas. +o allexportdesativa esse recurso.

set -o allexport
source conf-file
set +o allexport

9
Funciona como um encanto! Mesmo se o .envarquivo tiver comentários. Obrigado!
Slava Fomin II

9
E em uma linhaset -o allexport; source conf-file; set +o allexport
HarlemSquirrel 15/12

1
Essa é uma ótima maneira de ler um arquivo de propriedades, quando o plug-in Jenkins EnvInject não funciona. Obrigado!
Teresa Peters

21
@CMCDragonkai, para POSIX, seria set -a; . conf-file; set +a.
Charles Duffy

3
Este método funciona se as variáveis ​​de ambiente tiverem espaços. Muitos dos outros não. Enquanto o método eval () faz, eu também fico um pouco weirded usando eval
CommandZ

139
set -a
. ./env.txt
set +a

Se env.txté como:

VAR1=1
VAR2=2
VAR3=3
...

Explicações -a é equivalente a allexport . Em outras palavras, todas as atribuições de variáveis ​​no shell são exportadas para o ambiente (para serem usadas por vários processos filhos). Mais informações podem ser encontradas na documentação do conjunto :

-a     Cada variável ou função criada ou modificada recebe o atributo de exportação e é marcada para exportação para o ambiente dos comandos subseqüentes.

Usar '+' em vez de '-' faz com que essas opções sejam desativadas. As opções também podem ser usadas na chamada do shell. O conjunto atual de opções pode ser encontrado em $ -.


Você pode explicar o -a e + a?
Otto

11
@Otto -aé equivalente a allexport. Em outras palavras, todas as atribuições de variáveis ​​no shell são exportinseridas no ambiente (para serem usadas por vários processos filhos). Consulte também este artigo gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Dan Kowalczyk

33

A allexportopção é mencionada em algumas outras respostas aqui, para as quais set -aé o atalho. Fornecer o .env realmente é melhor do que repetir linhas e exportar porque permite comentários, linhas em branco e até variáveis ​​de ambiente geradas por comandos. Meu .bashrc inclui o seguinte:

# .env loading in the shell
dotenv () {
  set -a
  [ -f .env ] && . .env
  set +a
}

# Run dotenv on login
dotenv

# Run dotenv on every new directory
cd () {
  builtin cd $@
  dotenv
}

3
Parece bom, mas você descarrega variáveis ​​de ambiente quando sai do diretório?
Bastian Venthur 01/08/19

1
Não desarmar variáveis, e isso nunca foi um problema. Meus aplicativos tendem a usar nomes de variáveis ​​distintos e, se houver sobreposição, eu os configurarei em branco nesse .env com VAR=.
GSF

26
eval $(cat .env | sed 's/^/export /')

1
O uso eval $(cat .env | sed 's/^[^$]/export /')permite ter linhas vazias para melhor legibilidade.
Mario Uher 25/07/2015

2
Acho que cat .env | sed 's/^[^$]/export /'retira o caráter inicial. Ou seja, para um arquivo A=foo\nB=bar\nque recebo export =foo\nexport =bar\n. Isso funciona melhor para pular linhas em branco: cat .env | sed '/^$/! s/^/export /'.
Owen S.

(Noto também por uma questão de golfistas de código UNIX que você não precisa catem ambos os casos: eval $(sed 's/^/export /' .env)funciona tão bem.)
Owen S.

21

Eu achei a maneira mais eficiente é:

export $(xargs < .env)

Explicação

Quando temos um .envarquivo como este:

key=val
foo=bar

correr xargs < .envvai ficarkey=val foo=bar

então teremos um export key=val foo=bare é exatamente o que precisamos!

Limitação

  1. Ele não lida com casos em que os valores têm espaços neles. Comandos como env produzem esse formato. - @Shardj

3
Ele não lida com casos em que os valores têm espaços neles. Comandos como envproduzem esse formato.
Shardj 31/03

19

Aqui está outra sedsolução, que não executa eval ou requer ruby:

source <(sed -E -n 's/[^#]+/export &/ p' ~/.env)

Isso adiciona exportação, mantendo os comentários nas linhas começando com um comentário.

conteúdo .env

A=1
#B=2

amostra de execução

$ sed -E -n 's/[^#]+/export &/ p' ~/.env
export A=1
#export B=2

Achei isso especialmente útil ao construir um arquivo para carregar em um arquivo de unidade systemd, comEnvironmentFile .


não suporta várias linhas no OSX
Abdennour TOUMI

17

Promovi a resposta de user4040650 porque é simples e permite comentários no arquivo (ou seja, linhas começando com #), o que é altamente desejável para mim, pois é possível adicionar comentários explicando as variáveis. Apenas reescrevendo no contexto da pergunta original.

Se o script for chamado conforme indicado minientrega.sh prac1:, o minientrega.sh poderá ter:

set -a # export all variables created next
source $1
set +a # stop exporting

# test that it works
echo "Ficheros: $MINIENTREGA_FICHEROS"

O seguinte foi extraído da documentação do conjunto :

Esse recurso é tão complicado que merece sua própria seção. set permite alterar os valores das opções do shell e definir os parâmetros posicionais ou exibir os nomes e valores das variáveis ​​do shell.

set [--abefhkmnptuvxBCEHPT] [-o nome da opção] [argumento…] set [+ abefhkmnptuvxBCEHPT] [+ o nome da opção] [argumento…]

Se nenhuma opção ou argumento for fornecido, set exibirá os nomes e valores de todas as variáveis ​​e funções do shell, classificadas de acordo com o código do idioma atual, em um formato que pode ser reutilizado como entrada para definir ou redefinir as variáveis ​​definidas no momento. Variáveis ​​somente leitura não podem ser redefinidas. No modo POSIX, apenas variáveis ​​de shell são listadas.

Quando as opções são fornecidas, elas definem ou desativam os atributos do shell. As opções, se especificadas, têm os seguintes significados:

-a Cada variável ou função criada ou modificada recebe o atributo de exportação e é marcada para exportação para o ambiente dos comandos subseqüentes.

E isso também:

Usar '+' em vez de '-' faz com que essas opções sejam desativadas. As opções também podem ser usadas na chamada do shell. O conjunto atual de opções pode ser encontrado em $ -.


14

Melhorando a resposta de Silas Paul

exportar as variáveis ​​em um subshell as torna locais para o comando.

(export $(cat .env | xargs) && rails c)


Em seguida, você pode usar isso (set -a; source dev.env; set +a; rails c)para também obter os benefícios do fornecimento (por exemplo, o script pode ser executado).
wacha

12

SAVE=$(set +o | grep allexport) && set -o allexport && . .env; eval "$SAVE"

Isso salvará / restaurará suas opções originais, sejam elas quais forem.

O uso set -o allexporttem a vantagem de ignorar corretamente os comentários sem uma regex.

set +opor si só gera todas as suas opções atuais em um formato que o bash pode executar posteriormente. Também útil: set -opor si só, gera todas as suas opções atuais em formato amigável para humanos.


2
Eu provavelmente exec env -i bashlimparia o ambiente existente antes de chamar, evalse você precisar desconfigurar variáveis ​​definidas apenas dentro .env.
b4hand

11

A maneira mais curta que encontrei:

Seu .envarquivo:

VARIABLE_NAME="A_VALUE"

Então apenas

. ./.env && echo ${VARIABLE_NAME}

Bônus: Por ser uma linha curta, é muito útil em package.jsonarquivos

  "scripts": {
    "echo:variable": ". ./.env && echo ${VARIABLE_NAME}"
  }

E se você tiver muitas variáveis?
Madeo

@Madeo você pode adicionar tantas linhas como você quer, da mesma forma que a linhaVARIABLE_NAME="A_VALUE"
Flavien Volken

9

Mais simples:

  1. pegue o conteúdo do arquivo
  2. remova todas as linhas em branco (basta separar algumas coisas)
  3. remova quaisquer comentários (apenas no caso de você adicionar alguns ...)
  4. adicionar exporta todas as linhas
  5. eval a coisa toda

eval $(cat .env | sed -e /^$/d -e /^#/d -e 's/^/export /')

Outra opção (você não precisa executar eval(graças a @Jaydeep)):

export $(cat .env | sed -e /^$/d -e /^#/d | xargs)

Por fim, se você quiser tornar sua vida MUITO fácil, adicione isso ao seu ~/.bash_profile:

function source_envfile() { export $(cat $1 | sed -e /^$/d -e /^#/d | xargs); }

(TENHA CERTEZA DE RECOLOCAR AS CONFIGURAÇÕES DO BASH !!! source ~/.bash_profileou .. basta criar uma nova guia / janela e resolver o problema), você chama assim:source_envfile .env


2
Eu tive que ler .env texto da variável segredo gitlab para um gasoduto: Com base na sua solução este comando funcionou para mim: source <( echo $(sed -E -n 's/[^#]+/ &/ p' <(echo "${2}" | tr -d '\r')) );. De alguma forma, o gitlab salva a variável secreta com um retorno de carro do Windows, então eu tive que apará-la com tr -d '\r'.
metanerd

6

Você pode usar seu script original para definir as variáveis, mas é necessário chamá-lo da seguinte maneira (com ponto independente):

. ./minientrega.sh

Também pode haver um problema com a cat | while readabordagem. Eu recomendaria usar a abordagem while read line; do .... done < $FILE.

Aqui está um exemplo de trabalho:

> cat test.conf
VARIABLE_TMP1=some_value

> cat run_test.sh
#/bin/bash
while read line; do export "$line";
done < test.conf
echo "done"

> . ./run_test.sh
done

> echo $VARIABLE_TMP1
some_value

Ao contrário da maioria das outras respostas, esta solução não é avaliada test.confcomo um arquivo de script. Isso torna tudo melhor. É mais seguro não permitir scripts, a menos que você realmente precise, especialmente se alguém não perceber o que está acontecendo (ou esquecer).
meustrus

5

Com base em outras respostas, aqui está uma maneira de exportar apenas um subconjunto de linhas em um arquivo, incluindo valores com espaços como PREFIX_ONE="a word":

set -a
. <(grep '^[ ]*PREFIX_' conf-file)
set +a

5

Aqui está minha variante:

  with_env() {
    (set -a && . ./.env && "$@")
  }

em comparação com as soluções anteriores:

  • ele não vaza variáveis ​​fora do escopo (os valores de .envnão são expostos ao chamador)
  • não clobber setopções
  • retorna o código de saída do comando executado
  • usa posix compatível set -a
  • usa em .vez de sourceevitar o basismo
  • comando não é chamado se o .envcarregamento falhar
with_env rails console

Você também pode executar em linha (as variáveis ​​estão expostas à sua sessão atual do terminal): set -a && . ./.env && "$@" && echo "your comand here"
Giovanne Afonso

4

Eu trabalho com docker-composite e .envarquivos no Mac e queria importar o arquivo para o .envmeu bash shell (para teste), e a "melhor" resposta aqui foi acionar a seguinte variável:

.env

NODE_ARGS=--expose-gc --max_old_space_size=2048

Solução

Então acabei usando evale envolvendo meus env var defs entre aspas simples.

eval $(grep -v -e '^#' .env | xargs -I {} echo export \'{}\')

Versão do Bash

$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.


2

Tenho problemas com as soluções sugeridas anteriormente:

  • A solução do @ anubhava torna a gravação de arquivos de configuração amigável do bash muito irritante muito rápido e também - você pode não querer sempre exportar sua configuração.
  • A solução @Silas Paul é interrompida quando você tem variáveis ​​que possuem espaços ou outros caracteres que funcionam bem com valores entre aspas, mas $()que causam confusão.

Aqui está minha solução, que ainda é muito terrível para a IMO - e não resolve o problema "exportar apenas para um filho" abordado por Silas (embora você provavelmente possa executá-la em um sub-shell para limitar o escopo):

source .conf-file
export $(cut -d= -f1 < .conf-file)

2

Meus requisitos eram:

  • arquivo .env simples sem exportprefixos (para compatibilidade com dotenv)
  • valores de suporte entre aspas: TEXT = "alpha bravo charlie"
  • comentários de suporte prefixados com # e linhas vazias
  • universal para mac / BSD e linux / GNU

Versão de trabalho completa compilada a partir das respostas acima:

  set -o allexport
  eval $(grep -v '^#' .env | sed 's/^/export /')
  set +o allexport

1
qual é o sentido de "-o allexport" se você os anexa com "export" de qualquer maneira?
il - ya

2

Primeiro, crie um arquivo de ambiente que terá todo o par de valores-chave dos ambientes abaixo e o nomeie como quiser no meu caso, env_var.env

MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"

Em seguida, crie um script que exporte todas as variáveis ​​de ambiente para o ambiente python como abaixo e nomeie-o como export_env.sh

#!/usr/bin/env bash

ENV_FILE="$1"
CMD=${@:2}

set -o allexport
source $ENV_FILE
set +o allexport

$CMD

Esse script pegará o primeiro argumento como o arquivo de ambiente, exportará toda a variável de ambiente nesse arquivo e executará o comando depois disso.

USO:

./export_env.sh env_var.env python app.py

1

Me deparei com esse encadeamento quando estava tentando reutilizar o Docker --env-files em uma concha. Seu formato não é compatível com o bash, mas é simples name=value:, sem citação, sem substituição. Eles também ignoram linhas em branco e #comentários.

Eu não consegui obtê-lo compatível com posix, mas aqui está um que deve funcionar em shell do tipo bash (testado no zsh no OSX 10.12.5 e no bash no Ubuntu 14.04):

while read -r l; do export "$(sed 's/=.*$//' <<<$l)"="$(sed -E 's/^[^=]+=//' <<<$l)"; done < <(grep -E -v '^\s*(#|$)' your-env-file)

Ele não tratará três casos no exemplo dos documentos vinculados acima:

  • bash: export: `123qwe=bar': not a valid identifier
  • bash: export: `org.spring.config=something': not a valid identifier
  • e ele não manipulará a sintaxe de passagem (simples FOO)

1

Espaços em branco no valor

Há muitas ótimas respostas aqui, mas eu encontrei todas sem suporte para espaço em branco no valor:

DATABASE_CLIENT_HOST=host db-name db-user 0.0.0.0/0 md5

Encontrei 2 soluções que funcionam com esses valores com suporte para linhas e comentários vazios.

Um baseado na resposta sed e @ javier-buzzi :

source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x "&"/g' .env)

E um com linha de leitura em um loop baseado na resposta @ john1024

while read -r line; do declare -x "$line"; done < <(egrep -v "(^#|^\s|^$)" .env)

A chave aqui está em usar declare -xe colocar linha entre aspas duplas. Eu não sei por que, mas quando você reformata o código do loop em várias linhas, ele não funciona - eu não sou programador de bash, apenas juntei esses, ainda é mágico para mim :)


1
Eu tive que modificar a sedsolução para fazê-la funcionar. Mas primeiro alguma explicação: -eé a abreviação de --expression, que apenas informa sedquais operações executar. -e /^$/dexclui as linhas vazias da saída (não o arquivo). -e /^#/dexclui os comentários do bash (linhas que começam com #) da saída. 's/.*/declare -x "&"/g'substitui (substitui) as linhas restantes por declare -x "ENV_VAR="VALUE"". Quando você compra isso, pelo menos para mim, não funciona. Em vez disso, tive que usar source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x &/g' .env)para remover o "invólucro extra .
jcasner

Não uso ENV_VAR="lorem ipsum", ENV_VAR=lorem ipsumsem aspas, no arquivo .env. Agora não sei por que, mas isso provavelmente foi problemático em outras ferramentas que analisam esse arquivo. E em vez de lorem ipsumterminar com "lorem ipsum"valor - entre aspas. Thx para as explicações :)
Janusz Skonieczny

1
Se fosse minha escolha, eu também não usaria ENV_VAR="lorem ipsum". No meu caso de uso, meu provedor de hospedagem gera esse arquivo com base em algumas opções de configuração definidas e insere aspas duplas. Então, sou forçado a contornar isso. Obrigado por sua ajuda aqui - economizei muito tempo tentando descobrir as sedopções corretas !
jcasner

1

tente algo assim

for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done

1
t=$(mktemp) && export -p > "$t" && set -a && . ./.env && set +a && . "$t" && rm "$t" && unset t

Como funciona

  1. Crie arquivo temporário.
  2. Grave todos os valores atuais das variáveis ​​de ambiente no arquivo temp.
  3. Ative a exportação de todas as variáveis ​​declaradas no script de origem para o ambiente.
  4. Leia o .envarquivo. Todas as variáveis ​​serão exportadas para o ambiente atual.
  5. Desative a exportação de todas as variáveis ​​declaradas no script de origem para o ambiente.
  6. Leia o conteúdo do arquivo temporário. Cada linha teria declare -x VAR="val"que exportaria cada uma das variáveis ​​para o ambiente.
  7. Remova o arquivo temporário.
  8. Desative a variável que contém o nome do arquivo temporário.

Recursos

  • Preserva valores das variáveis ​​já definidas no ambiente
  • .env pode ter comentários
  • .env pode ter linhas vazias
  • .envnão requer cabeçalho ou rodapé especial, como nas outras respostas ( set -ae set +a)
  • .envnão requer ter exportpara todo valor
  • one-liner


0

Meu arquivo .env se parece com:

DATABASE_URI="postgres://sa:***@localhost:5432/my_db"
VARIABLE_1="SOME_VALUE"
VALIABLE_2="123456788"

Usando as maneiras do @henke , o valor exportado acaba contendo as aspas"

"postgres://sa:***@localhost:5432/my_db"
"SOME_VALUE"
"123456788"

Mas quero que o valor exportado contenha apenas:

postgres://sa:***@localhost:5432/my_db
SOME_VALUE
123456788

Para corrigi-lo, edito o comando para excluir as aspas:

export $(grep -v '^#' dev.env | tr --delete '"' | xargs -d '\n')

0

Este lida com espaços no RHS e pula vars 'estranhos', como definições de módulo bash (com '()' neles):

echo "# source this to set env vars" > $bld_dir/.env
env | while read line; do
    lhs="${line%%=*}"
    rhs="${line#*=}"
    if [[ "$lhs" =~ ^[0-9A-Za-z_]+$ ]]; then
        echo "export $lhs=\"$rhs\"" >> $bld_dir/.env
    fi
done
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.