Imposta le variabili di ambiente dal file delle coppie chiave / valore


514

TL; DR: Come posso esportare un set di coppie chiave / valore da un file di testo nell'ambiente shell?


Per la cronaca, di seguito è riportata la versione originale della domanda, con esempi.

Sto scrivendo uno script in bash che analizza i file con 3 variabili in una determinata cartella, questa è una di queste:

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

Questo file è archiviato in ./conf/prac1

Il mio script minientrega.sh quindi analizza il file utilizzando questo codice:

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

Ma quando eseguo minientrega.sh prac1dalla riga di comando non imposta le variabili di ambiente

Ho anche provato a utilizzare source ./conf/$1ma lo stesso problema si applica ancora

Forse c'è un altro modo per farlo, ho solo bisogno di usare le variabili d'ambiente del file che passo come argomento del mio script.




Questa è un'ottima domanda ma è formulata in modo troppo specifico, con nomi di variabili particolari ("MINIENTREGA_FECHALIMITE"? Cosa significa?) E numeri (3). La domanda generale è semplicemente "Come posso esportare un set di coppie chiave / valore da un file di testo nell'ambiente shell".
Dan Dascalescu,

Inoltre, questo è già stato risposto su unix.SE ed è probabilmente più in argomento lì.
Dan Dascalescu il

Risposte:


209

Problema con il vostro approccio è l' exportnel whileciclo sta accadendo in un guscio di sub, e quelli variabile non sarà disponibile in shell corrente (shell genitore del ciclo while).

Aggiungi il exportcomando nel file stesso:

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

Quindi è necessario originare il file nella shell corrente usando:

. ./conf/prac1

O

source ./conf/prac1

4
Anche se la lettura del file linea per linea e passante per ciascuna linea exportnon è ideale, il problema può essere risolto semplicemente utilizzando il reindirizzamento ingresso sul ciclo: while read line; do ... ; done < ./conf/$1.
Chepner,

4
E se non proviene da un file, usa< <(commands that generate output)
o11c

5
Hai una soluzione più pulita , ho una preferenza perset -o allexport
heralight,

2
Se si utilizza questo file .env tra sistemi, l'inserimento exportlo spezzerebbe per cose come Java, SystemD o altri strumenti
FilBot3

1
awk '{print "export " $0}' envfilecomando di convenienza per anteporre l'esportazione all'inizio di ogni riga
Shardj

888

Questo potrebbe essere utile:

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

Il motivo per cui lo uso è se voglio testare .envcose nella mia console di binari.

gabrielf ha trovato un buon modo per mantenere le variabili locali. Questo risolve il potenziale problema quando si passa da un progetto all'altro.

env $(cat .env | xargs) rails

Ho provato questo con bash 3.2.51(1)-release


Aggiornare:

Per ignorare le righe che iniziano con #, usa questo (grazie al commento di Pete ):

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

E se vuoi unsettutte le variabili definite nel file, usa questo:

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

Aggiornare:

Per gestire anche i valori con spazi, utilizzare:

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

su sistemi GNU - oppure:

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

su sistemi BSD.


6
Grazie, mi piace che questo non richieda anteporre nulla al file - consente la compatibilità con il formato .env di Foreman (Procfile).
natevw,

29
Ho trovato la soluzione: env $ (cat .env | xargs) rails
gabrielf

4
Questo sembra non funzionare se uno dei valori env ha degli spazi, anche se non sono sicuro di quale sia il modo migliore / desiderato per specificare i valori con gli spazi. github.com/ddollar/foreman/issues/56 dice che dovrebbe funzionare come, export $(cat .env)ma non so come fare con gli spazi.
Dan Benamy,

6
@BenjaminWheeler GNU linux ha -dper impostare il delimitatore, quindi ci sto provando env $(cat .env | xargs -d '\n') rails, ma continua ad errori con un file non trovato se .envha spazi. Qualche idea sul perché questo non funziona?
Bailey Parker,

19
Ecco una variazione più breveeval $(cat .env) rails
manalang

413

-o allexportconsente di esportare tutte le seguenti definizioni delle variabili. +o allexportdisabilita questa funzione.

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

9
Funziona come un fascino! Anche se il .envfile contiene commenti. Grazie!
Slava Fomin II,

9
E in una rigaset -o allexport; source conf-file; set +o allexport
Harlem Squirrel il

1
Questo è un ottimo modo per leggere in un file delle proprietà, quando il plug-in EnvInject di Jenkins non funziona. Grazie!
Teresa Peters,

21
@CMCDragonkai, per POSIX, lo sarebbe set -a; . conf-file; set +a.
Charles Duffy,

3
Questo metodo funziona se le variabili di ambiente contengono spazi. Molti degli altri no. Mentre il metodo eval () funziona, anche io sono un po 'fuori di
testa

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

Se env.txtè come:

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

Spiegazioni -a equivale a allexport . In altre parole, ogni assegnazione di variabili nella shell viene esportata nell'ambiente (per essere utilizzata da più processi figlio). Ulteriori informazioni sono disponibili nella documentazione integrata di Set :

-a A     ogni variabile o funzione creata o modificata viene assegnato l'attributo export e contrassegnato per l'esportazione nell'ambiente di comandi successivi.

L'uso di "+" anziché di "-" comporta la disattivazione di queste opzioni. Le opzioni possono anche essere utilizzate su invocazione della shell. L'attuale set di opzioni può essere trovato in $ -.


Puoi spiegare -a e + a?
Otto,

11
@Otto -aè equivalente a allexport. In altre parole, ogni assegnazione di variabili nella shell èexport nell'ambiente (per essere utilizzata da più processi figlio). Vedi anche questo articolo gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Dan Kowalczyk,

33

L' allexportopzione è menzionata in un paio di altre risposte qui, per cui set -aè il collegamento. Sourcing di .env è davvero meglio che passare in rassegna le righe e esportare perché consente commenti, righe vuote e persino variabili d'ambiente generate dai comandi. Il mio .bashrc include quanto segue:

# .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
Sembra carino, ma scarichi le variabili d'ambiente quando lasci la directory?
Bastian Venthur,

1
Non deseleziono le variabili e non è mai stato un problema. Le mie app tendono a usare nomi di variabili distinti e, in caso di sovrapposizione, li imposterò in bianco in quel .env con VAR=.
GSF,

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

1
L'uso eval $(cat .env | sed 's/^[^$]/export /')consente di avere righe vuote per una migliore leggibilità.
Mario Uher,

2
Trovo che cat .env | sed 's/^[^$]/export /'toglie il carattere iniziale. Vale a dire per un file A=foo\nB=bar\nche ottengo export =foo\nexport =bar\n. Questo funziona meglio per saltare righe vuote: cat .env | sed '/^$/! s/^/export /'.
Owen S.

(Noto anche per il bene dei golfisti del codice UNIX che non è necessario catin entrambi i casi: eval $(sed 's/^/export /' .env)funziona altrettanto bene.)
Owen S.

21

Ho trovato il modo più efficiente è:

export $(xargs < .env)

Spiegazione

Quando abbiamo un .envfile come questo:

key=val
foo=bar

la corsa xargs < .envavràkey=val foo=bar

quindi avremo un export key=val foo=bar ed è esattamente ciò di cui abbiamo bisogno!

Limitazione

  1. Non gestisce i casi in cui i valori contengono spazi. Comandi come env producono questo formato. - @Shardj

3
Non gestisce i casi in cui i valori contengono spazi. Comandi come envprodurre questo formato.
Shardj

19

Ecco un'altra sedsoluzione, che non esegue eval o richiede ruby:

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

Ciò aggiunge l'esportazione, mantenendo i commenti sulle righe che iniziano con un commento.

Contenuti .env

A=1
#B=2

esecuzione del campione

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

Ho trovato questo particolarmente utile quando si costruisce un file simile per il caricamento in un file di unità di sistema, conEnvironmentFile .


non supporta più righe in OSX
Abdennour TOUMI

17

Ho votato a favore della risposta di user4040650 perché è sia semplice che consente commenti nel file (ovvero righe che iniziano con #), il che è altamente desiderabile per me, poiché è possibile aggiungere commenti che spiegano le variabili. Basta riscrivere nel contesto della domanda originale.

Se lo script è chiamato come indicato minientrega.sh prac1:, quindi minientrega.sh potrebbe avere:

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

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

Quanto segue è stato estratto dalla documentazione impostata :

Questo built-in è così complicato che merita una sua sezione. set consente di modificare i valori delle opzioni della shell e impostare i parametri posizionali o di visualizzare i nomi e i valori delle variabili della shell.

set [--abefhkmnptuvxBCEHPT] [-o nome-opzione] [argomento ...] set [+ abefhkmnptuvxBCEHPT] [+ o nome-opzione] [argomento ...]

Se non vengono fornite opzioni o argomenti, set visualizza i nomi e i valori di tutte le variabili e funzioni della shell, ordinate in base alla locale corrente, in un formato che può essere riutilizzato come input per l'impostazione o il ripristino delle variabili attualmente impostate. Le variabili di sola lettura non possono essere ripristinate. In modalità POSIX, sono elencate solo le variabili shell.

Quando vengono fornite le opzioni, impostano o annullano gli attributi della shell. Le opzioni, se specificate, hanno i seguenti significati:

-a A ogni variabile o funzione creata o modificata viene assegnato l'attributo export e contrassegnato per l'esportazione nell'ambiente di comandi successivi.

E anche questo:

L'uso di "+" anziché di "-" comporta la disattivazione di queste opzioni. Le opzioni possono anche essere utilizzate su invocazione della shell. L'attuale set di opzioni può essere trovato in $ -.


14

Migliorare la risposta di Silas Paul

l'esportazione delle variabili su una subshell le rende locali al comando.

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


Quindi puoi usarlo (set -a; source dev.env; set +a; rails c)per avere anche i vantaggi del sourcing (ad es. Lo script può essere eseguito).
wacha,

12

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

Ciò salverà / ripristinerà le opzioni originali, qualunque esse siano.

L'utilizzo set -o allexportha il vantaggio di saltare correttamente i commenti senza regex.

set +oda solo restituisce tutte le opzioni correnti in un formato che bash potrà successivamente eseguire. Utile anche: set -oda solo, genera tutte le opzioni attuali in un formato a misura d'uomo.


2
Probabilmente desidero exec env -i bashcancellare l'ambiente esistente prima di chiamare evalse è necessario annullare l' impostazione delle variabili che sono solo impostate all'interno .env.
b4hand,

11

Il modo più breve che ho trovato:

Il tuo .envfile:

VARIABLE_NAME="A_VALUE"

Quindi basta

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

Bonus: poiché è un one-liner corto, è molto utile nel package.jsonfile

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

Che ne dici se hai molte variabili?
Madeo,

@Madeo puoi aggiungere tutte le righe che vuoi, allo stesso modo della lineaVARIABLE_NAME="A_VALUE"
Flavien Volken,

9

Più semplice:

  1. prendi il contenuto del file
  2. rimuovi le righe vuote (basta che tu abbia separato alcune cose)
  3. rimuovi eventuali commenti (nel caso in cui tu ne abbia aggiunto alcuni ...)
  4. aggiungere exporta tutte le righe
  5. eval l'intera cosa

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

Un'altra opzione (non è necessario eseguire eval(grazie a @Jaydeep)):

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

Infine, se vuoi semplificarti davvero la vita, aggiungi questo al tuo ~/.bash_profile:

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

(ASSICURARSI DI RICARICARE LE IMPOSTAZIONI DI BASH !!! source ~/.bash_profileo ... basta creare una nuova scheda / finestra e risolvere il problema) la si chiama così:source_envfile .env


2
Ho dovuto leggere il testo da .env variabile segreto gitlab per una pipeline: Sulla base della sua soluzione di questo comando ha funzionato per me: source <( echo $(sed -E -n 's/[^#]+/ &/ p' <(echo "${2}" | tr -d '\r')) );. In qualche modo gitlab salva la variabile segreta con un ritorno a capo di Windows, quindi ho dovuto tagliarlo con tr -d '\r'.
Metanerd,

6

È possibile utilizzare lo script originale per impostare le variabili, ma è necessario chiamarlo nel modo seguente (con punto autonomo):

. ./minientrega.sh

Inoltre potrebbe esserci un problema con l' cat | while readapproccio. Consiglierei di usare l'approccio while read line; do .... done < $FILE.

Ecco un esempio funzionante:

> 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

A differenza della maggior parte delle altre risposte, questa soluzione non viene valutata test.confcome file di script. Questo lo rende migliore. È più sicuro non consentire gli script a meno che tu non ne abbia effettivamente bisogno, specialmente se qualcuno non si rende conto che sta succedendo (o dimentica).
Meustrus

5

Sulla base di altre risposte, ecco un modo per esportare solo un sottoinsieme di righe in un file, inclusi valori con spazi come PREFIX_ONE="a word":

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

5

Ecco la mia variante:

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

rispetto alle soluzioni precedenti:

  • non perde le variabili al di fuori dell'ambito (i valori di .envnon sono esposti al chiamante)
  • non ostruisce le setopzioni
  • restituisce il codice di uscita del comando eseguito
  • usa posix compatibile set -a
  • usa .invece di sourceevitare il bashismo
  • il comando non viene richiamato se il .envcaricamento non riesce
with_env rails console

Puoi anche eseguire in linea (le variabili sono esposte alla tua sessione terminale corrente): set -a && . ./.env && "$@" && echo "your comand here"
Giovanne Afonso,

4

Lavoro con docker-compose e .envfile su Mac e volevo importare la .envmia shell bash (per i test), e la risposta "migliore" qui è stata la seguente:

.env

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

Soluzione

Così ho finito per usare evale racchiudere i miei valori env var tra virgolette singole.

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

Versione Bash

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


2

Ho problemi con le soluzioni suggerite in precedenza:

  • La soluzione di @ anubhava rende la scrittura di file di configurazione bash friendly molto fastidiosa molto velocemente, e potresti anche non voler esportare sempre la tua configurazione.
  • La soluzione @Silas Paul si interrompe quando si hanno variabili con spazi o altri caratteri che funzionano bene nei valori tra virgolette, ma $()creano un disastro.

Ecco la mia soluzione, che è ancora piuttosto terribile IMO - e non risolve il problema "esporta solo su un figlio" risolto da Silas (anche se probabilmente puoi eseguirlo in una sotto-shell per limitare l'ambito):

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

2

Le mie esigenze erano:

  • semplice file .env senza exportprefissi (per compatibilità con dotenv)
  • valori di supporto tra virgolette: TEXT = "alpha bravo charlie"
  • commenti di supporto preceduti da # e righe vuote
  • universale per mac / BSD e linux / GNU

Versione di lavoro completa compilata dalle risposte sopra:

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

1
che senso ha "-o allexport" se li anteponi comunque con "export"?
il - ya,

2

Innanzitutto, crea un file di ambiente che avrà tutta la coppia chiave-valore degli ambienti come di seguito e chiamalo come preferisci nel mio caso env_var.env

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

Quindi crea uno script che esporterà tutte le variabili di ambiente per l'ambiente Python come di seguito e chiamalo come export_env.sh

#!/usr/bin/env bash

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

set -o allexport
source $ENV_FILE
set +o allexport

$CMD

Questo script prenderà il primo argomento come file di ambiente, quindi esporterà tutte le variabili di ambiente in quel file e quindi eseguirà il comando.

USO:

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

1

Mi sono imbattuto in questo thread quando stavo provando a riutilizzare Docker --env-filein una shell. Il loro formato non è compatibile con bash ma è semplice: name=valuenessuna citazione, nessuna sostituzione. Ignorano anche righe e #commenti vuoti .

Non sono riuscito a renderlo compatibile con posix, ma eccone uno che dovrebbe funzionare con shell tipo bash (testato in zsh su OSX 10.12.5 e bash su Ubuntu 14.04):

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

Essa non sarà gestire tre casi nell'esempio dalla documentazione collegate di cui sopra:

  • bash: export: `123qwe=bar': not a valid identifier
  • bash: export: `org.spring.config=something': not a valid identifier
  • e non gestirà la sintassi passthrough (una nuda FOO)

1

Spazi bianchi nel valore

Ci sono molte ottime risposte qui, ma le ho trovate tutte prive di supporto per gli spazi bianchi nel valore:

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

Ho trovato 2 soluzioni che funzionano con tali valori con supporto per righe e commenti vuoti.

Uno basato sulla risposta sed e @ javier-buzzi :

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

E uno con la riga di lettura in un ciclo basato sulla risposta @ john1024

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

La chiave qui sta nell'usare declare -xe mettere la linea tra virgolette. Non so perché, ma quando riformatti il ​​codice del ciclo su più righe non funzionerà - non sono un programmatore bash, ho appena divorato insieme questi, è ancora magico per me :)


1
Ho dovuto modificare la sedsoluzione per farlo funzionare. Ma prima una spiegazione: -eè l'abbreviazione di --expression, che dice solo sedquali operazioni eseguire. -e /^$/delimina le righe vuote dall'output (non il file). -e /^#/delimina i commenti bash (righe che iniziano con #) dall'output. 's/.*/declare -x "&"/g'sostituisce (sostituisce) le righe rimanenti con declare -x "ENV_VAR="VALUE"". Quando lo fonte, almeno per me, non ha funzionato. Invece, ho dovuto usare source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x &/g' .env), per rimuovere l' "involucro aggiuntivo .
jcasner,

Non uso ENV_VAR="lorem ipsum", ho ENV_VAR=lorem ipsum, senza virgolette nel file .env. Ora non sono sicuro del perché, ma questo è stato probabilmente problematico in altri strumenti che analizzano questo file. E invece di lorem ipsumho finito con il "lorem ipsum"valore - con le virgolette. Grazie per le spiegazioni :)
Janusz Skonieczny l'

1
Se fosse stata una mia scelta, non avrei usato ENV_VAR="lorem ipsum"neanche. Nel mio caso d'uso, il mio provider di hosting genera questo file in base ad alcune opzioni di configurazione che ho impostato e inseriscono le doppie virgolette. Quindi, sono costretto a aggirare il problema. Grazie per il tuo aiuto qui - mi hai fatto risparmiare un sacco di tempo nel tentativo di elaborare da solo le sedopzioni corrette !
jcasner,

1

prova qualcosa del genere

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

Come funziona

  1. Crea file temporaneo.
  2. Scrivi tutti i valori delle variabili di ambiente correnti nel file temporaneo.
  3. Abilita l'esportazione di tutte le variabili dichiarate nello script dei sorgenti nell'ambiente.
  4. Leggi il .envfile. Tutte le variabili verranno esportate nell'ambiente corrente.
  5. Disabilita l'esportazione di tutte le variabili dichiarate nello script dei sorgenti nell'ambiente.
  6. Leggi il contenuto del file temporaneo. Ogni riga dovrebbe declare -x VAR="val"esportare ciascuna delle variabili in ambiente.
  7. Rimuovi il file temporaneo.
  8. Deseleziona il nome del file temporaneo di mantenimento della variabile.

Caratteristiche

  • Conserva i valori delle variabili già impostate nell'ambiente
  • .env può avere commenti
  • .env può avere righe vuote
  • .envnon richiede intestazioni o piè di pagina speciali come nelle altre risposte ( set -aeset +a )
  • .envnon richiede di avere exportper ogni valore
  • one-liner


0

Il mio file .env è simile a:

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

Usando i modi di @henke , il valore esportato finisce per contenere le virgolette"

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

Ma voglio che il valore esportato contenga solo:

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

Per risolverlo, modifico il comando per eliminare le virgolette:

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

0

Questo affronta gli spazi sull'RHS e salta i vars "strani" come le definizioni del modulo bash (con "()"):

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.