Установить переменные окружения из файла пар ключ / значение

514

TL; DR: как экспортировать набор пар ключ / значение из текстового файла в среду оболочки?


Для справки ниже приведена оригинальная версия вопроса с примерами.

Я пишу скрипт на bash, который анализирует файлы с 3 переменными в определенной папке, это одна из них:

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но та же проблема по-прежнему применяется

Возможно, есть какой-то другой способ сделать это, мне просто нужно использовать переменные окружения файла, который я передаю в качестве аргумента моего скрипта.

hugo19941994
источник
То же самое в unix: unix.stackexchange.com/questions/31797/…
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
То же самое с Руби: stackoverflow.com/questions/2139080/… , драгоценный камень, который делает это: github.com/bkeepers/dotenv
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
Это отличный вопрос, но он сформулирован слишком конкретно, с конкретными именами переменных («MINIENTREGA_FECHALIMITE»? Что это значит?) И числами (3). Общий вопрос прост: «Как экспортировать набор пар ключ / значение из текстового файла в среду оболочки».
Дан Даскалеску
Кроме того, на unix.SE уже дан ответ, и, возможно, он более актуален .
Дан Даскалеску

Ответы:

209

Проблема с вашим подходом заключается exportв том, что whileцикл in происходит в вложенной оболочке, и эти переменные не будут доступны в текущей оболочке (родительской оболочке цикла 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
Хотя чтение файла строка за строкой и проходящей каждую линию , чтобы exportне является идеальным, проблема также может быть решена просто используя перенаправление ввода на петле: while read line; do ... ; done < ./conf/$1.
Чепнер
4
И если это не из файла, используйте< <(commands that generate output)
o11c
5
У вас есть более чистое решение , я предпочитаюset -o allexport
heralight
2
Если использовать этот файл .env между системами, вставка exportсломает его для таких вещей, как Java, SystemD или другие инструменты
FilBot3
1
awk '{print "export " $0}' envfileудобная команда для добавления экспорта в начало каждой строки
Shardj
889

Это может быть полезно:

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

Причина, по которой я это использую, заключается в том, что я хочу проверить .envматериал в моей консоли rails.

Габриэль нашел хороший способ сохранить переменные локальными. Это решает потенциальную проблему при переходе от проекта к проекту.

env $(cat .env | xargs) rails

Я проверил это с bash 3.2.51(1)-release


Обновить:

Чтобы игнорировать строки, начинающиеся с #, используйте это (благодаря комментарию Пита ):

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
29
Я придумал решение: env $ (cat .env | xargs) rails
gabrielf
4
Это, кажется, не работает, если любое из значений env имеет пробелы, хотя я на самом деле не уверен, какой лучший / желательный способ указать значения с пробелами. github.com/ddollar/foreman/issues/56 говорит, что это должно работать так, export $(cat .env)но я не знаю, как справиться с пробелами.
Дэн Бенами
6
@BenjaminWheeler GNU linux имеет -dдля установки разделителя, так что я пытаюсь env $(cat .env | xargs -d '\n') rails, но он все равно ошибки с файлом не найден, если .envесть пробелы. Есть идеи, почему это не работает?
Бэйли Паркер
19
Вот более короткая вариацияeval $(cat .env) rails
Маналанг
413

-o allexportпозволяет экспортировать все следующие определения переменных. +o allexportотключает эту функцию.

set -o allexport
source conf-file
set +o allexport
user4040650
источник
9
Работает как шарм! Даже если в .envфайле есть комментарии. Спасибо!
Слава Фомин II
9
И в одной строкеset -o allexport; source conf-file; set +o allexport
HarlemSquirrel
1
Это отличный способ чтения в файле свойств, когда плагин Jenkins EnvInject не работает. Спасибо!
Тереза ​​Петерс
21
@CMCDragonkai, для POSIX это было бы set -a; . conf-file; set +a.
Чарльз Даффи
3
Этот метод работает, если в переменных среды есть пробелы. Многие другие нет. В то время как метод eval () делает, я также немного утомлен, используя eval
CommandZ
139
set -a
. ./env.txt
set +a

Если env.txtэто как:

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

Пояснения -a эквивалентны allexport . Другими словами, каждое присвоение переменной в оболочке экспортируется в среду (для использования несколькими дочерними процессами). Дополнительную информацию можно найти во встроенной документации Set :

-a     Каждая переменная или функция, которая создается или изменяется, получает атрибут экспорта и помечается для экспорта в среду последующих команд.

Использование «+» вместо «-» приводит к отключению этих параметров. Опции также могут быть использованы при вызове оболочки. Текущий набор параметров можно найти в $ -.

Дэн Ковальчик
источник
Можете ли вы объяснить -a и + a?
Отто
11
@ Отто -aэквивалентно allexport. Другими словами, каждое присвоение переменной в оболочке exportвводится в среду (для использования несколькими дочерними процессами). Также смотрите эту статью gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Дэн Ковальчик
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
}
GSF
источник
3
Это выглядит хорошо, но вы выгружаете переменные окружения, когда покидаете каталог?
Бастиан Вентур
1
Я не сбрасываю переменные, и это никогда не было проблемой. Мои приложения, как правило, используют имена переменных, которые различны, и если есть совпадения, я установлю их пустыми в этом .env с VAR=.
GSF
26
eval $(cat .env | sed 's/^/export /')
Selvan
источник
1
Использование eval $(cat .env | sed 's/^[^$]/export /')позволяет вам иметь пустые строки для лучшей читаемости.
Марио Ухер
2
Я считаю, что cat .env | sed 's/^[^$]/export /'лишает первоначального персонажа. Т.е. за файл A=foo\nB=bar\nя получаю export =foo\nexport =bar\n. Это работает лучше для пропуска пустых строк: cat .env | sed '/^$/! s/^/export /'.
Оуэн С.
(Я также отмечаю, что для игроков в гольф с кодом UNIX вам не нужно catни в одном из случаев: eval $(sed 's/^/export /' .env)работает
Оуэн С.
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производить этот формат.
Шардж
19

Вот еще одно sedрешение, которое не запускает eval или не требует 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

Я нашел это особенно полезным при создании такого файла для загрузки в файл системного модуля, сEnvironmentFile .

tutuDajuju
источник
не поддерживает несколько строк в 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 имя-опции] [аргумент…] set [+ abefhkmnptuvxBCEHPT] [+ o-имя-опции] [аргумент…]

Если параметры или аргументы не предоставлены, set отображает имена и значения всех переменных и функций оболочки, отсортированных в соответствии с текущей локалью, в формате, который можно использовать повторно в качестве входных данных для установки или сброса текущих установленных переменных. Переменные только для чтения не могут быть сброшены. В режиме POSIX перечислены только переменные оболочки.

Когда параметры предоставлены, они устанавливают или отменяют атрибуты оболочки. Опции, если указаны, имеют следующие значения:

-a Каждая переменная или функция, которая создается или изменяется, получает атрибут экспорта и помечается для экспорта в среду последующих команд.

И это также:

Использование «+» вместо «-» приводит к отключению этих параметров. Опции также могут быть использованы при вызове оболочки. Текущий набор параметров можно найти в $ -.

Nagev
источник
14

Улучшение ответа Сайласа Павла

экспорт переменных в подоболочку делает их локальными для команды.

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

Джейди Соланки
источник
Затем вы можете использовать это, (set -a; source dev.env; set +a; rails c)чтобы также иметь преимущества поиска (например, скрипт может выполняться).
вача
12

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

Это сохранит / восстановит ваши исходные параметры, какими бы они ни были.

Использование set -o allexportимеет то преимущество, что правильно пропускает комментарии без регулярных выражений.

set +oСам по себе выводит все ваши текущие параметры в формате, который позже может выполнить bash. Также удобно: set -oсамо по себе выводит все ваши текущие параметры в удобном для человека формате.

jwfearn
источник
2
Я бы, вероятно, exec env -i bashочистил существующую среду перед вызовом, evalесли вам нужно сбросить переменные, которые установлены только внутри .env.
b4hand
11

Самый короткий путь, который я нашел:

Ваш .envфайл:

VARIABLE_NAME="A_VALUE"

Тогда просто

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

Бонус: поскольку это короткий однострочный текст, он очень полезен в package.jsonфайле

  "scripts": {
    "echo:variable": ". ./.env && echo ${VARIABLE_NAME}"
  }
Флавиен Волкен
источник
Как насчет того, если у вас много переменных?
Мадео
@Madeo вы можете добавить столько строк, сколько хотите, так же, как и строкиVARIABLE_NAME="A_VALUE"
Flavien Volken
9

Simpler:

  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
Я должен был прочитать .env текст из gitlab секретной переменной для трубопровода: на основе вашего решения эта команда работала для меня source <( echo $(sed -E -n 's/[^#]+/ &/ p' <(echo "${2}" | tr -d '\r')) );. Каким-то образом gitlab сохраняет секретную переменную с возвратом каретки Windows, поэтому мне пришлось урезать его tr -d '\r'.
metanerd
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
Элан Руусамяэ
источник
Вы также можете запустить inline (переменные доступны для текущего сеанса терминала): set -a && . ./.env && "$@" && echo "your comand here"
Джованна Афонсо
4

Я работаю с docker-compose и .envфайлами на Mac и хотел импортировать их .envв мою оболочку bash (для тестирования), и «лучшим» ответом здесь было срабатывание следующей переменной:

.env

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

Решение

Так что я закончил тем, что использовал evalи заключил свои env var def в одинарные кавычки.

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

Версия Bash

$ /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 ломается, когда у вас есть переменные с пробелами или другими символами, которые хорошо работают в кавычках, но $()мешают.

Вот мое решение, которое все еще довольно ужасно для ИМО - и не решает проблему «экспорта только одному дочернему элементу», решаемую Сайласом (хотя вы, вероятно, можете запустить ее в под-оболочке, чтобы ограничить область действия):

source .conf-file
export $(cut -d= -f1 < .conf-file)
Guss
источник
2

Мои требования были:

  • простой .env файл без exportпрефиксов (для совместимости с dotenv)
  • вспомогательные значения в кавычках: TEXT = "альфа браво чарли"
  • поддерживающие комментарии с префиксом # и пустыми строками
  • универсальный для Mac / BSD и Linux / GNU

Полная рабочая версия составлена ​​из ответов выше:

  set -o allexport
  eval $(grep -v '^#' .env | sed 's/^/export /')
  set +o allexport
Alex
источник
1
какой смысл "-o allexport", если вы в любом случае добавляете к ним "export"?
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

Я наткнулся на эту тему, когда пытался повторно использовать Docker --env-fileв оболочке. Их формат не совместим с bash, но он прост: name=valueбез цитирования, без подстановки. Они также игнорируют пустые строки и #комментарии.

Я не смог получить его с помощью posix-совместимости, но вот тот, который должен работать в bash-подобных оболочках (протестировано в zsh на OSX 10.12.5 и bash на Ubuntu 14.04):

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

Он не будет обрабатывать три случая в примере из документов, связанных выше:

  • 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 и @ хавьер-BUZZI ответ :

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

И один с строкой чтения в цикле на основе ответа @ john1024

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

Ключевым моментом здесь является использование declare -xи размещение строки в двойных кавычках. Я не знаю почему, но когда вы переформатируете код цикла в несколько строк, это не сработает - я не программист bash, я просто сожрал их вместе, это по-прежнему волшебно для меня :)

Януш Сконечны
источник
1
Мне пришлось изменить sedрешение, чтобы заставить его работать. Но сначала несколько объяснений: -eэто сокращение --expression, которое просто говорит, sedкакие операции нужно предпринять. -e /^$/dудаляет пустые строки из вывода (не из файла). -e /^#/dудаляет комментарии bash (строки, начинающиеся с #) из вывода. 's/.*/declare -x "&"/g'заменяет (заменяет) оставшиеся строки на declare -x "ENV_VAR="VALUE"". Когда вы получаете это, по крайней мере для меня, это не сработало. Вместо этого мне пришлось использовать source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x &/g' .env), чтобы удалить лишнюю "обертку.
января
Я не использую ENV_VAR="lorem ipsum", у меня есть ENV_VAR=lorem ipsum, без кавычек в файле .env. Теперь я не уверен, почему, но это, вероятно, было проблематично в других инструментах, которые анализируют этот файл. И вместо этого lorem ipsumя закончил со "lorem ipsum"значением - с кавычками. Спасибо за объяснения :)
Януш Skonieczny
1
Если бы это был мой выбор, я бы тоже не использовал ENV_VAR="lorem ipsum". В моем случае мой провайдер хостинга генерирует этот файл на основе некоторых опций конфигурации, которые я установил, и они вставляют двойные кавычки. Итак, я вынужден обойти это. Спасибо за вашу помощь здесь - сэкономил мне много времени, пытаясь выработать правильные sedварианты самостоятельно!
jcasner
1

попробуй что-нибудь подобное

for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done
gaozhidf
источник
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)
  • .envне требует иметь exportдля каждого значения
  • один лайнер
Алекс Скрипник
источник
0

Если вы получаете сообщение об ошибке, поскольку одна из ваших переменных содержит значение, содержащее пробелы, вы можете попытаться сбросить bash IFS(Внутренний разделитель полей), \nчтобы позволить bash интерпретировать cat .envрезультат как список параметров для envисполняемого файла.

Пример:

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
PATb
источник