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

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

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

Ответ 1

Проблема с вашим подходом заключается в том, что 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

Ответ 2

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

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

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

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

env $(cat .env | xargs) rails

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


Обновление:

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

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.

Ответ 3

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

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

Ответ 4

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

Если env.txt выглядит следующим образом:

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

Ответ 5

Опция 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 [email protected]
  dotenv
}

Ответ 6

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

Ответ 7

Вот еще одно решение sed, которое не запускает eval или требует ruby:

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

Это добавляет экспорт, сохраняя комментарии к строкам, начинающимся с комментария.

.env contents

A=1
#B=2

образец пробега

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

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

Ответ 8

У меня есть upvoted user4040650 ответ, потому что он прост и позволяет комментарии в файле (то есть строки, начинающиеся С#), что очень желательно для меня, поскольку комментарии, объясняющие переменные, могут быть добавлены. Просто переписывание в контексте исходного вопроса.

Если script запрограммирован как указано: 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 [--abefhkmnptuvxBCEHPT] [-o option-name] [аргумент...] установлен [+ abefhkmnptuvxBCEHPT] [+ o option-name] [аргумент...]

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

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

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

И это также:

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

Ответ 9

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

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

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

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

Ответ 10

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

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

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

Ответ 11

Simpler:

  • захватить содержимое файла
  • удалите все пустые строки (просто вы можете отделить некоторые вещи)
  • удалите все комментарии (просто добавьте некоторые из них...)
  • добавить export ко всем строкам
  • 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

Ответ 12

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

Ваш файл .env:

VARIABLE_NAME="A_VALUE"

Тогда просто

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

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

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

Ответ 13

Вы можете использовать свой оригинальный script для установки переменных, но вы должны называть его следующим образом (с автономной точкой):

. ./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

Ответ 14

Основываясь на других ответах, вот способ экспортировать только подмножество строк в файле, включая значения с пробелами типа PREFIX_ONE="a word":

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

Ответ 15

У меня есть проблемы с ранее предложенными решениями:

  • Решение @anubhava делает записи bash дружественных файлов конфигурации очень раздражающими очень быстро, а также - вы можете не захотеть всегда экспортировать свою конфигурацию.
  • Решение @Silas Paul ломается, когда у вас есть переменные, у которых есть пробелы или другие символы, которые хорошо работают в цитируемых значениях, но $() создает беспорядок.

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

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

Ответ 16

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

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

Затем создайте скрипт, который будет экспортировать все переменные среды для среды Python, как export_env.sh ниже, и назовите его как 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

Ответ 17

Белые пространства в значении

Здесь есть много отличных ответов, но я обнаружил, что им не хватает поддержки белого пространства в стоимости:

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 отвечает

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

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

Ответ 18

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

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

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

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

Ответ 19

Я работаю с файлами 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.

Ответ 20

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

Пример:

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

См. также:

Ответ 22

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

Я не мог получить его совместимым с posix, но вот тот, который должен работать в оболочках bash -like (проверен в 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)

Ответ 23

Если вы хотите загрузить ваш.env файл в исполняемый процесс внутри кода Visual Studio, вы можете добавить ссылку на ваш.ENV файл в свой launch.json используя свойство envFile:

"configurations": [
    {
        "name": "Launch server.js with .env",
        "type": "node",
        "request": "launch",
        "envFile": "${workspaceRoot}/.env",
        ...
    }
]