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

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

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

52 ответа

Решение

Проблема с вашим подходом 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

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

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

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

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

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.

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

set -o allexport
source conf-file
set +o allexport
set -a
. ./env.txt
set +a

Если env.txt как:

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

Я нашел самый эффективный способ:

export $(xargs < .env)

Объяснение

Когда у нас есть .env файл вроде этого:

key=val
foo=bar

пробег xargs < .env получите key=val foo=bar

так что мы получим export key=val foo=bar и это именно то, что нам нужно!

Ограничение

  1. Он не обрабатывает случаи, когда значения содержат пробелы. Такие команды, как env, создают этот формат. - @Shardj

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
}

Проблема в том, что он требует, чтобы файл имел правильный синтаксис bash, а некоторые специальные символы испортят его: =, ", ', <, >, и другие. Поэтому в некоторых случаях вы не можете просто

      source development.env

Однако эта версия поддерживает все специальные символы в значениях:

      set -a
source <(cat development.env | \
    sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g")
set +a

Объяснение:

  • -a означает, что каждая переменная bash станет переменной среды
  • /^#/d удаляет комментарии (строки, начинающиеся с #)
  • /^\s*$/d удаляет пустые строки, включая пробелы
  • "s/'/'\\\''/g" заменяет каждую цитату на '\'', который в bash представляет собой трюк для создания цитаты :)
  • "s/=\(.*\)/='\1'/g" конвертирует каждый a=b в a='b'

В результате вы можете использовать специальные символы :)

Чтобы отладить этот код, замените source с cat и вы увидите, что производит эта команда.

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

Вот еще один 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,

Не совсем уверен, почему или что я пропустил, но после того, как я прочитал большинство ответов и потерпел неудачу. Я понял, что с этим файлом.env:

MY_VAR="hello there!"
MY_OTHER_VAR=123

Я мог бы просто сделать это:

source .env
echo $MY_VAR

Выходы: Hello there!

Кажется, отлично работает в Ubuntu linux.

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

Ваш .env файл:

VARIABLE_NAME="A_VALUE"

Тогда просто

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

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

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

Я проголосовал за ответ 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 Каждая переменная или функция, которая создается или изменяется, получает атрибут экспорта и помечается для экспорта в среду последующих команд.

И это также:

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

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

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

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

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

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

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

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

Вот мой вариант:

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

по сравнению с предыдущими решениями:

  • он не пропускает переменные за пределы области видимости (значения из .env не выставляются на звонилку)
  • не трепится set параметры
  • возвращает код выхода выполненной команды
  • использует posix-совместимый set -a
  • использует . вместо того source избегать башизма
  • команда не вызывается, если .env загрузка не удалась
with_env rails console

Если env поддерживает -S вариант можно использовать символы новой строки или escape-символы, такие как \n или же \t(см. env):

      env -S "$(cat .env)" command

.env пример файла:

      KEY="value with space\nnewline\ttab\tand
multiple
lines"

Тест:

      env -S "$(cat .env)" sh -c 'echo "$KEY"'

Используйте shdotenv

Поддержка dotenv для оболочки и POSIX-совместимой спецификации синтаксиса .env
https://github.com/ko1nksm/shdotenv

      eval "$(shdotenv)"

Применение

      Usage: shdotenv [OPTION]... [--] [COMMAND [ARG]...]

  -d, --dialect DIALECT  Specify the .env dialect [default: posix]
                           (posix, ruby, node, python, php, go, rust, docker)
  -s, --shell SHELL      Output in the specified shell format [default: posix]
                           (posix, fish)
  -e, --env ENV_PATH     Location of the .env file [default: .env]
                           Multiple -e options are allowed
  -o, --overload         Overload predefined environment variables
  -n, --noexport         Do not export keys without export prefix
  -g, --grep PATTERN     Output only those that match the regexp pattern
  -k, --keyonly          Output only variable names
  -q, --quiet            Suppress all output
  -v, --version          Show the version and exit
  -h, --help             Show this message and exit

Требования

shdotenv - это сценарий оболочки для одного файла со встроенным сценарием awk.

  • Оболочка POSIX (тире, bash, ksh, zsh и т. Д.)
  • awk (gawk, nawk, mawk, busybox awk)

Извините, что добавляю еще один ответ, но поскольку он упрощен и работает во многих случаях, попробуйте:

      export $(< ~/my/.env)

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

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

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

Я работаю с 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.
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 для каждого значения
  • один лайнер

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

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

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

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

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

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

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

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

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

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

Мой.env:

#!/bin/bash
set -a # export all variables

#comments as usual, this is a bash script
USER=foo
PASS=bar

set +a #stop exporting variables

Вызов:

source .env; echo $USER; echo $PASS

Ссылка https://unix.stackexchange.com/questions/79068/how-to-export-variables-that-are-set-all-at-once

Вот мой взгляд на это. У меня были следующие требования:

  • Игнорировать прокомментированные строки
  • Разрешить пробелы в значении
  • Разрешить пустые строки
  • Возможность передать пользовательский файл env при использовании по умолчанию.env
  • Разрешить экспорт, а также запуск команд в строке
  • Выйти, если файл env не существует
source_env() {
  [ "$#" -eq 1 ] && env="$1" || env=".env"
  [ -f "$env" ] || { echo "Env file $env doesn't exist"; return 1; }
  eval $(grep -Ev '^#|^$' "$env" | sed -e 's/=\(.*\)/="\1/g' -e 's/$/"/g' -e 's/^/export /')
}

Использование после сохранения функции в вашем.bash_profile или аналогичном:

source_env                # load default .env file
source_env .env.dev       # load custom .env file
(source_env && COMMAND)   # run command without saving vars to environment

На основе Хавьера и некоторых других комментариев.

Моя версия:

Я распечатываю файл, удаляю закомментированные строки, пустые строки и разделяю ключ / значение со знаком «=». Затем я просто применяю команду экспорта.

Преимущество этого решения заключается в том, что файл может содержать специальные символы в значениях, такие как каналы, теги html и т. Д., И значение не нужно заключать в кавычки, как файл реальных свойств.

      # Single line version
cat myenvfile.properties | grep -v '^#' | grep '=' | while read line; do IFS=\= read k v <<< $line; export $k="$v"; done

# Mutliline version:
cat myenvfile.properties | grep -v '^#' | grep '=' | while read line; do 
  IFS=\= read k v <<< $line
  export $k="$v"
done

Некоторые примечания:

  1. Файл «.env» должен иметь последовательность конца строки «LF».
  2. Избегайте использования динамических значений в переменных среды, таких какvariable1=$variable2@$variable3
  3. Избегайте использования цитат (") в переменных среды vavlue, напримерvariable="value"

Это лучший и самый короткий ответ

      source .env && export $(cut -d= -f1 < .env)

Изменено из @Dan Kowalczyk

Я положил это в ~/.bashrc.

set -a
. ./.env >/dev/null 2>&1
set +a

Кросс-совместимый очень хорошо с плагином dotenv Oh-my-Zsh. (Есть Oh-my-bash, но у него нет плагина dotenv.)

Другие вопросы по тегам