キーと値のペアのファイルから環境変数を設定する


513

TL; DR:キー/値ペアのセットをテキストファイルからシェル環境にエクスポートするにはどうすればよいですか?


参考までに、質問の元のバージョンと例を以下に示します。

私は特定のフォルダー内の3つの変数を持つファイルを解析するスクリプトをbashで書いています。これはそのうちの1つです。

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

このファイルは./conf/prac1に保存されています

スクリプトminientrega.shは、次のコードを使用してファイルを解析します。

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

しかしminientrega.sh prac1、コマンドラインで実行すると、環境変数が設定されません

私も使用してみましたsource ./conf/$1が、同じ問題がまだ適用されます

これを行うには他の方法があるかもしれません。スクリプトの引数として渡すファイルの環境変数を使用する必要があるだけです。




これはすばらしい質問ですが、特定の変数名( "MINIENTREGA_FECHALIMITE"?どういう意味ですか?)と数値(3)を使用して、具体的に表現されています。一般的な質問は、「テキストファイルからシェル環境にキーと値のペアのセットをエクスポートするにはどうすればよいですか」です。
Dan Dascalescu 2018年

また、これは既にunix.SEで回答されており、間違いなくそこで話題になっています。
Dan Dascalescu、2018

回答:


209

あなたのアプローチの問題exportは、whileループ内がサブシェルで発生しており、それらの変数が現在のシェル(whileループの親シェル)で使用できないことです。

exportファイル自体にコマンドを追加します。

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

次に、次のコマンドを使用して、現在のシェルのファイルを読み込む必要があります。

. ./conf/prac1

または

source ./conf/prac1

4
ファイルを1行ずつ読み込んで各行に渡すのexportは理想的ではありませんが、ループで入力リダイレクトを使用するだけで問題を解決できますwhile read line; do ... ; done < ./conf/$1
chepner

4
そして、それがファイルからのものでない場合は、< <(commands that generate output)
o11c

5
あなたはよりクリーンなソリューションを持っています、私は好みがありますset -o allexport
heralight

2
システム間でこの.envファイルを使用している場合、挿入するexportと、Java、SystemD、またはその他のツールなどでファイルが壊れます
FilBot3

1
awk '{print "export " $0}' envfileすべての行の先頭にエクスポートを
追加

888

これは役に立つかもしれません:

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

これを使用する理由は、テストしたい場合です .envは、Railsコンソールで。

gabrielfは変数をローカルに保つための良い方法を考え出しました。これにより、プロジェクト間を移動する際の潜在的な問題が解決されます。

env $(cat .env | xargs) rails

私はこれをテストしました bash 3.2.51(1)-release


更新:

で始まる行を無視するには#、これを使用します(Peteのコメントに感謝):

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

またunset、ファイルで定義されているすべての変数が必要な場合は、次のようにします。

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

更新:

スペースを含む値も処理するには、次を使用します。

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

GNUシステム-または:

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

BSDシステムの場合。


6
おかげで、これはファイルの前に何も追加する必要がないことが好きです— Foreman(Procfile).env形式との互換性を可能にします。
natevw 2014年

29
私は解決策を思いつきました:env $(cat .env | xargs)rails
gabrielf

4
env値のいずれかにスペースがある場合、これは機能しないようですが、スペースを使用して値を指定するための最良の/望ましい方法は実際にはわかりません。github.com/ddollar/foreman/issues/56は、それは同じように機能するはずだと述べてexport $(cat .env)いますが、スペースを処理する方法がわかりません。
Dan Benamy、2015年

6
@BenjaminWheeler GNU linuxは-d区切り文字を設定するためにあるのでenv $(cat .env | xargs -d '\n') rails、試してみました.envが、スペースがある場合、ファイルが見つからないというエラーが発生します。これが機能しない理由はありますか?
ベイリーパーカー

19
こちらが短いバリエーションですeval $(cat .env) rails
-manalang

413

-o allexport以下のすべての変数定義をエクスポートできるようにします。+o allexportこの機能を無効にします。

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

9
魅力的な作品!場合でも、.envファイルがそれにコメントしています。ありがとう!
Slava Fomin II

9
そして一行set -o allexport; source conf-file; set +o allexport
HarlemSquirrel

1
これは、Jenkins EnvInjectプラグインが機能しない場合に、プロパティファイルを読み取るための優れた方法です。ありがとう!
Teresa Peters

21
@ CMCDragonkai、POSIXの場合はになりますset -a; . conf-file; set +a
チャールズダフィー

3
この方法は、環境変数にスペースが含まれている場合に機能します。他の多くはしません。eval()メソッドは実行しますが、evalを使用して少しおかしくなります
CommandZ

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

env.txtような場合:

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

説明 -aはallexportと同等です。つまり、シェル内のすべての変数割り当てが環境にエクスポートされます(複数の子プロセスで使用されます)。詳細については、組み込みSetドキュメントをご覧ください。

-a     作成または変更された各変数または関数には、export属性が与えられ、後続のコマンドの環境へのエクスポート用にマークが付けられます。

「-」ではなく「+」を使用すると、これらのオプションがオフになります。オプションは、シェルの呼び出し時にも使用できます。現在のオプションのセットは$-にあります。


-aと+ aについて説明できますか?
オットー

11
@Ottoはと-a同等allexportです。言い換えると、シェル内のすべての変数割り当てexportは環境に送られます(複数の子プロセスで使用されます)。この記事も参照してくださいgnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Dan Kowalczyk

33

このallexportオプションについては、他のいくつかの回答で説明していますset -aが、これがショートカットです。コメント、空白行、さらにはコマンドによって生成された環境変数さえも許容するため、.envをソースとすることは、行をループしてエクスポートすることよりも優れています。私の.bashrcには以下が含まれています。

# .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
これは見た目はいいですが、ディレクトリを離れるときに環境変数をアンロードしますか?
Bastian Venthur 2017

1
私は変数の設定を解除していません、そしてそれは問題ではありませんでした。私のアプリは異なる変数名を使用する傾向があり、重複がある場合は、.envでを使用してそれらを空白に設定しますVAR=
gsf 2017

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

1
を使用eval $(cat .env | sed 's/^[^$]/export /')すると、読みやすくするために空の行を含めることができます。
Mario Uher

2
cat .env | sed 's/^[^$]/export /'最初の文字が取り除かれているのがわかります。つまり、A=foo\nB=bar\n取得したファイルの場合export =foo\nexport =bar\n。これは、空白行をスキップする場合に適していますcat .env | sed '/^$/! s/^/export /'
オーウェンS.

(また、UNIXコードゴルファーのためにcat、どちらの場合も必要ではないことに注意してくださいeval $(sed 's/^/export /' .env)。同様に機能します。)
Owen S.

21

私は最も効率的な方法を見つけました:

export $(xargs < .env)

説明

次の.envようなファイルがある場合:

key=val
foo=bar

実行がxargs < .env得られますkey=val foo=bar

だから私たちは得るでしょう、export key=val foo=barそしてそれはまさに私たちが必要とするものです!

制限

  1. 値にスペースが含まれている場合は処理されません。envなどのコマンドはこの形式を生成します。– @Shardj

3
値にスペースが含まれている場合は処理されません。などのコマンドenvはこの形式を生成します。
Shardj

19

sedevalを実行しない、またはrubyを必要としない別のソリューションを次に示します。

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

これはエクスポートを追加し、コメントで始まる行にコメントを保持します。

.envの内容

A=1
#B=2

サンプル実行

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

これは、systemdユニットファイルにEnvironmentFile読み込むためにそのようなファイルを作成するときに特に便利です。


OSXで複数行をサポートしない
Abdennour TOUMI

17

変数は簡単に説明できるのでuser4040650の回答に賛成しています。また、変数を説明するコメントを追加できるため、ファイル内のコメント(つまり、#で始まる行)を許可しています。元の質問のコンテキストで書き直すだけです。

スクリプトがminientrega.sh prac1次のように呼び出された場合:minientrega.shは次のようになります。

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

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

以下は、セットのドキュメントから抽出されました。

このビルトインは非常に複雑なので、独自のセクションに値します。setを使用すると、シェルオプションの値を変更して位置パラメータを設定したり、シェル変数の名前や値を表示したりできます。

set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument…] set [+ abefhkmnptuvxBCEHPT] [+ o option-name] [argument…]

オプションまたは引数が指定されていない場合、setは、現在設定されている変数を設定またはリセットするための入力として再利用できる形式で、現在のロケールに従ってソートされたすべてのシェル変数および関数の名前と値を表示します。読み取り専用変数はリセットできません。POSIXモードでは、シェル変数のみがリストされます。

オプションを指定すると、シェル属性が設定または設定解除されます。オプションが指定されている場合、次の意味があります。

-a作成または変更された各変数または関数には、export属性が与えられ、後続のコマンドの環境へのエクスポート用にマークが付けられます。

そしてこれも:

「-」ではなく「+」を使用すると、これらのオプションがオフになります。オプションは、シェルの呼び出し時にも使用できます。現在のオプションのセットは$-にあります。


14

サイラス・ポールの答えを改善する

サブシェルで変数をエクスポートすると、変数がコマンドに対してローカルになります。

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


次に、これ(set -a; source dev.env; set +a; rails c)を使用して、ソーシングの利点(スクリプトを実行できるなど)も利用できます。
wacha

12

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

これにより、元のオプションが何であれ、保存/復元されます。

を使用set -o allexportすると、正規表現なしでコメントを適切にスキップできるという利点があります。

set +o単独で、現在のすべてのオプションを、bashが後で実行できる形式で出力します。また、便利です。set -oそれ自体で、現在のすべてのオプションを人に優しい形式で出力します。


2
内でのみ設定されている変数の設定を解除する必要がある場合は、exec env -i bash呼び出す前に既存の環境をクリアするでしょう。eval.env
b4hand 2015

11

私が見つけた最短の方法:

あなたの.envファイル:

VARIABLE_NAME="A_VALUE"

じゃあ

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

おまけ:短いワンライナーなので、package.jsonファイルで非常に便利です。

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

変数がたくさんある場合はどうでしょうか?
Madeo

あなたが望むよう、あなたは、多くの行と行と同じように追加することができます@MadeoVARIABLE_NAME="A_VALUE"
Flavien Volken

9

よりシンプル:

  1. ファイルのコンテンツを取得する
  2. 空白行を削除します(何かを分離した場合に備えて)
  3. コメントを削除します(いくつか追加した場合に備えて...)
  4. exportすべての行に追加
  5. eval 全部

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

別のオプション(実行する必要はありませんeval(@Jaydeepに感謝)):

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

最後に、あなたの人生を本当に簡単にしたいなら、これをあなたに追加してください~/.bash_profile

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

(BASH設定を再読み込みすることを確認してください!!! source ~/.bash_profileまたは、新しいタブ/ウィンドウを作成して問題を解決してください)次のように呼び出します。source_envfile .env


2
パイプラインのgitlabシークレット変数から.envテキストを読み取る必要がありました:ソリューションに基づいて、このコマンドは私のために機能しました:source <( echo $(sed -E -n 's/[^#]+/ &/ p' <(echo "${2}" | tr -d '\r')) );。どういうわけかgitlabは秘密の変数をウィンドウのキャリッジリターンで保存するので、でトリミングする必要がありましたtr -d '\r'
metanerd 2017年

6

元のスクリプトを使用して変数を設定できますが、次の方法で(スタンドアロンのドットを使用して)呼び出す必要があります。

. ./minientrega.sh

また、cat | while readアプローチに問題があるかもしれません。このアプローチを使用することをお勧めしますwhile read line; do .... done < $FILE

これが実際の例です:

> 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

他のほとんどの回答とは異なり、このソリューションはtest.confスクリプトファイルとして評価されません。それはそれをより良くします。特に誰かがそれが起こっている(または忘れている)ことに気付いていない場合は特に、実際に必要としない限り、スクリプトを許可しない方が安全です。
meustrus

5

他の答えに基づいて、ここにファイルの行のサブセットのみをエクスポートする方法がありますPREFIX_ONE="a word"

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

5

これが私の変種です:

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

以前のソリューションと比較して:

  • スコープ外に変数をリークしません(からの値.envは呼び出し元に公開されません)
  • setオプションを壊さない
  • 実行されたコマンドの終了コードを返します
  • posix互換を使用 set -a
  • バシズムを回避する.代わりに使用しますsource
  • .envロードが失敗した場合、コマンドは呼び出されません
with_env rails console

また、(変数は現在の端末セッションにさらされている)インライン実行することができます: set -a && . ./.env && "$@" && echo "your comand here"
Giovanneアフォンソ

4

.envはMac でdocker-composeとファイルを使用してい.envて、(テスト用に)bashシェルにをインポートしたいと思っていました。

.env

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

解決

そのため、私はを使用してeval、env var defsを一重引用符で囲みました。

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

バッシュバージョン

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


2

以前に提案された解決策に問題があります:

  • @anubhavaのソリューションにより、bashフレンドリーな構成ファイルの書き込みが非常に煩わしくなり、また、常に構成をエクスポートしたくない場合があります。
  • @Silas Paulソリューションは、引用符で囲まれた値で適切に機能するスペースまたはその他の文字を含む変数があると壊れますが$()、混乱します。

ここに私の解決策がありますが、それはまだかなりひどいIMOです-そしてSilasによって対処された「1つの子にのみエクスポートする」問題を解決しません(スコープを制限するためにサブシェルで実行することができます):

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

2

私の要件は:

  • exportプレフィックスなしの単純な.envファイル(dotenvとの互換性のため)
  • 引用符で囲んだ値:TEXT = "alpha bravo charlie"
  • #で始まるコメントと空行のサポート
  • mac / BSDとlinux / GNUの両方に共通

上記の回答からコンパイルされた完全に機能するバージョン:

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

1
とにかくそれらに「export」を付加した場合、「-o allexport」の意味は何ですか?
il--ya

2

最初に、以下のような環境のすべてのキーと値のペアを含む環境ファイルを作成し、私の場合は好きな名前を付けます env_var.env

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

次に、以下のようなpython環境のすべての環境変数をエクスポートするスクリプトを作成し、次のように名前を付けます export_env.sh

#!/usr/bin/env bash

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

set -o allexport
source $ENV_FILE
set +o allexport

$CMD

このスクリプトは、最初の引数を環境ファイルとして取り、そのファイル内のすべての環境変数をエクスポートしてから、コマンドを実行します。

使用法:

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

1

--env-fileシェルでDockerを再利用しようとしたときにこのスレッドに出くわしました。 それらの形式はbash互換ではありませんが、シンプルです:name=value引用符なし、置換なし。また、空白行や#コメントも無視されます。

私はそれをposix互換にすることができませんでしたが、bashのようなシェルで動作するはずのものです(OSX 10.12.5のzshとUbuntu 14.04のbashでテストされています):

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

それはしません上記のリンクのドキュメントからの例では3つのケースを処理します。

  • bash: export: `123qwe=bar': not a valid identifier
  • bash: export: `org.spring.config=something': not a valid identifier
  • そしてそれはパススルー構文を処理しません(裸FOO

1

値の空白

ここには多くの素晴らしい答えがありますが、値の空白のサポートがすべて不足していることがわかりました。

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

空の行とコメントをサポートして、そのような値で機能する2つのソリューションを見つけました。

sedと@ javier-buzziの回答に基づくもの:

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

そして、@ john1024の回答に基づいてループ内の行を読み取る1つ

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

ここで重要なのは、declare -x行を使用して二重引用符で囲むことです。理由はわかりませんが、ループコードを複数行に再フォーマットしても機能しません—私はbashプログラマーではないので、これらをいじりましたが、それでも私には魔法です:)


1
sedソリューションを機能させるには、ソリューションを変更する必要がありました。ただし、最初にいくつかの説明を示します。これ-eは、の略で--expressionsed実行する操作を示すだけです。-e /^$/d空の行を(ファイルではなく)出力から削除します。-e /^#/dbashコメント(#で始まる行)を出力から削除します。's/.*/declare -x "&"/g'残りの行をに置き換えdeclare -x "ENV_VAR="VALUE""ます。あなたがこれを調達したとき、少なくとも私にとっては、それはうまくいきませんでした。代わりに、source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x &/g' .env)余分な"ラッパーを削除するために、を使用する必要がありました。
jcasner

私が使用していないENV_VAR="lorem ipsum"、私が持っているENV_VAR=lorem ipsum.envファイル内の引用符なし、。なぜなのかはわかりませんが、このファイルを解析する他のツールではおそらく問題がありました。そして、lorem ipsum私は"lorem ipsum"価値で終わりました-引用符で。説明のためのTHX :)
Janusz Skonieczny

1
それが私の選択であったなら、私はENV_VAR="lorem ipsum"どちらも使用しません。私のユースケースでは、私のホスティングプロバイダーは、設定したいくつかの構成オプションに基づいてこのファイルを生成し、二重引用符を挿入します。だから、私はそれを回避することを余儀なくされています。ここであなたの助けをありがとう-私は正しいsedオプションを自分で解決しようとする多くの時間を節約しました!
jcasner 2018

1

このようなものを試してください

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

使い方

  1. 一時ファイルを作成します。
  2. 現在のすべての環境変数値を一時ファイルに書き込みます。
  3. ソーススクリプトで宣言されたすべての変数を環境にエクスポートできるようにします。
  4. .envファイルを読み取ります。すべての変数が現在の環境にエクスポートされます。
  5. ソーススクリプトで宣言されたすべての変数の環境へのエクスポートを無効にします。
  6. 一時ファイルの内容を読み取ります。すべての行declare -x VAR="val"で、各変数を環境にエクスポートします。
  7. 一時ファイルを削除します。
  8. 一時ファイル名を保持する変数の設定を解除します。

特徴

  • 環境にすでに設定されている変数の値を保持します
  • .env コメントを持つことができます
  • .env 空の行を含めることができます
  • .env他の回答のように特別なヘッダーやフッターは必要ありません(set -aおよびset +a
  • .envexportすべての値を持っている必要はありません
  • 一発ギャグ

0

変数の1つに空白を含む値が含まれているためにエラーが発生した場合は、bash IFS(内部フィールドセパレーター)をリセットし\nて、bash cat .envenv実行可能ファイルのパラメーターのリストとして結果を解釈できるようにします。

例:

IFS=$'\n'; env $(cat .env) rails c

以下も参照してください。


0

私の.envファイルは次のようになります。

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

@henkeの方法を使用すると、エクスポートされた値には引用符が含まれます"

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

しかし、私はエクスポートされた値に以下のみを含めたいです:

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

修正するには、コマンドを編集して引用符を削除します。

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

0

これは、RHSのスペースに対応し、bashモジュール定義などの「奇妙な」変数(「()」を含む)をスキップします。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.