TL; DR:如何将文本文件中的一组键/值对导出到shell环境中?
对于记录,下面是问题的原始版本,带有示例。
我正在用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
,但同样的问题仍然适用
也许有其他方法可以做到这一点,我只需要使用我传递的文件的环境变量作为我的脚本的参数。
答案 0 :(得分:625)
这可能会有所帮助:
export $(cat .env | xargs) && rails c
我使用它的原因是我想在rails控制台中测试.env
内容。
gabrielf想出了一个将变量保持在本地的好方法。这解决了从项目到项目的潜在问题。
env $(cat .env | xargs) rails
我已使用bash 3.2.51(1)-release
<强>更新强>
要忽略以#
开头的行,请使用此功能(感谢Pete's 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系统上。
答案 1 :(得分:283)
-o allexport
可以导出所有后续变量定义。 +o allexport
禁用此功能。
set -o allexport
source conf-file
set +o allexport
答案 2 :(得分:141)
您的方法问题是export
循环中的while
发生在子shell中,并且这些变量在当前shell(while循环的父shell)中不可用。
在文件中添加export
命令:
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
然后你需要使用以下命令在当前shell中的文件中输入:
. ./conf/prac1
OR
source ./conf/prac1
答案 3 :(得分:72)
set -a
. ./env.txt
set +a
如果env.txt
如下:
VAR1=1
VAR2=2
VAR3=3
...
答案 4 :(得分:38)
我发现最有效的方法是:
export $(xargs < .env)
当我们有一个.env
文件时,
key=val
foo=bar
运行xargs < .env
将获得key=val foo=bar
所以我们将得到一个export key=val foo=bar
,这正是我们所需要的!
答案 5 :(得分:25)
此处的其他几个答案中提到了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
}
答案 6 :(得分:21)
eval $(cat .env | sed 's/^/export /')
答案 7 :(得分:20)
这是另一个sed
解决方案,它不运行eval或需要ruby:
source <(sed -E -n 's/[^#]+/export &/ p' ~/.env)
这会添加导出,在注释开头的行上保留注释。
A=1
#B=2
$ sed -E -n 's/[^#]+/export &/ p' ~/.env
export A=1
#export B=2
我发现这在构建这样一个文件以便在systemd unit file, with EnvironmentFile
中加载时特别有用。
答案 8 :(得分:13)
我赞成了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 documentation:
这个内置非常复杂,值得拥有自己的部分。组 允许您更改shell选项的值并设置 位置参数,或显示shell的名称和值 变量
设置[--abefhkmnptuvxBCEHPT] [-o选项名称] [参数...]设置 [+ abefhkmnptuvxBCEHPT] [+ o option-name] [参数...]
如果未提供选项或参数,则set将显示所有shell的名称和值 变量和函数,根据当前语言环境排序,在 格式可以重复用作设置或重置的输入 当前设定的变量。只读变量无法重置。在POSIX中 模式,只列出了shell变量。
提供选项时,它们会设置或取消设置shell属性。 选项(如果指定)具有以下含义:
-a创建或修改的每个变量或函数都被赋予export属性并标记为导出到环境中 后续命令。
这也是:
使用“+”而不是“ - ”会导致关闭这些选项。该 在调用shell时也可以使用options。目前的设定 选项可以在$ - 。
中找到
答案 9 :(得分:11)
不完全确定为什么或我错过了什么,但是在大多数答案都失败之后却失败了。我意识到有了这个.env文件:
MY_VAR="hello there!"
MY_OTHER_VAR=123
我可以简单地做到这一点:
source .env
echo $MY_VAR
输出:Hello there!
似乎可以在Ubuntu linux上正常工作。
答案 10 :(得分:11)
改善Silas Paul的回答
在子shell上导出变量使它们成为命令的本地变量。
(export $(cat .env | xargs) && rails c)
答案 11 :(得分:11)
这是我的变体:
with_env() {
(set -a && . ./.env && "$@")
}
与先前的解决方案相比:
.env
中的值不会暴露给调用者)set
选项set -a
.
而非source
来避免暴力行为.env
加载失败,则不会调用with_env rails console
答案 12 :(得分:9)
简单:
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
答案 13 :(得分:8)
source
的问题在于它要求文件具有正确的 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
,您将看到此命令产生的结果。
答案 14 :(得分:5)
在其他答案的基础上,以下是一种仅导出文件中一行子集的方法,包括PREFIX_ONE="a word"
之类的空格值:
set -a
. <(grep '^[ ]*PREFIX_' conf-file)
set +a
答案 15 :(得分:5)
您可以使用原始脚本设置变量,但需要按以下方式调用它(使用独立点):
. ./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
答案 16 :(得分:5)
如果 env
支持 -S
选项,则可以使用换行符或转义字符,如 \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"'
答案 17 :(得分:3)
t=$(mktemp) && export -p > "$t" && set -a && . ./.env && set +a && . "$t" && rm "$t" && unset t
工作方式
.env
文件。所有变量都将导出到当前环境中。declare -x VAR="val"
,可将每个变量导出到环境中。功能
.env
可以发表评论.env
可以有空行.env
不需要像其他答案(set -a
和set +a
)中那样的特殊页眉或页脚.env
不需要每个值都有export
答案 18 :(得分:2)
我使用这个:
source <(cat .env \
| sed -E '/^\s*#.*/d' \
| tr '\n' '\000' \
| sed -z -E 's/^([^=]+)=(.*)/\1\x0\2/g' \
| xargs -0 -n2 bash -c 'printf "export %s=%q;\n" "${@}"' /dev/null)
首先删除评论:
sed -E '/^\s*#.*/d'
然后转换为空定界符而不是换行符:
tr '\n' '\000'
然后将null替换为null:
sed -z -E 's/^([^=]+)=(.*)/\1\x0\2/g'
然后将打印对打印到有效的带引号的bash导出中(对%q使用bash printf):
xargs -0 -n2 bash -c 'printf "export %s=%q;\n" "${@}"' /dev/null
然后将所有资源全部采购。
它几乎适用于所有带有特殊字符的情况。
答案 19 :(得分:2)
由@Dan Kowalczyk修改
我将其放在~/.bashrc
中。
set -a
. ./.env >/dev/null 2>&1
set +a
与Oh-my-Zsh的dotenv插件具有很好的交叉兼容性。 (有Oh-my-bash,但没有dotenv插件。)
答案 20 :(得分:2)
dotenv 支持 shell 和符合 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 脚本的单文件 shell 脚本。
答案 21 :(得分:1)
这里有很多很棒的答案,但我发现它们都缺乏对空白区域的支持:
DATABASE_CLIENT_HOST=host db-name db-user 0.0.0.0/0 md5
我找到了两个解决方案,这些解决方案可以支持空行和注释。
一个基于sed和@ javier-buzzi answer:
source <(sed -e /^$/d -e /^#/d -e 's/.*/declare -x "&"/g' .env)
一个基于@ john1024 answer
的循环读取行while read -r line; do declare -x "$line"; done < <(egrep -v "(^#|^\s|^$)" .env)
这里的关键是使用declare -x
并将行放在双引号中。我不知道为什么,但是当你将循环代码重新格式化为多行时它将不起作用 - 我不是bash程序员,我只是吞噬了这些,它对我来说仍然是神奇的:)
答案 22 :(得分:1)
我的要求是:
export
的简单.env文件(与dotenv兼容)根据以上答案编译的完整版本:
set -o allexport
eval $(grep -v '^#' .env | sed 's/^/export /')
set +o allexport
答案 23 :(得分:1)
我对之前建议的解决方案有疑问:
$()
会弄得一团糟。这是我的解决方案,这仍然是非常可怕的IMO - 并且没有解决'#34;仅导出给一个孩子&#34; Silas解决的问题(虽然您可以在子shell中运行它以限制范围):
source .conf-file
export $(cut -d= -f1 < .conf-file)
答案 24 :(得分:0)
我如何保存变量:
printenv | sed 's/\([a-zA-Z0-9_]*\)=\(.*\)/export \1="\2"/' > myvariables.sh
我如何加载它们
source myvariables.sh
答案 25 :(得分:0)
如果您打算将 exec
作为脚本的最后一个命令,您可以通过使用 execlineb
解释器获得一个附加选项。这是您脚本的最后一行的样子:
#!/bin/sh
...
exec envfile -I /etc/default/bla envfile /etc/default/bla-bla my_cmd
envfile ...
是来自 execline
套件的命令,它们依赖于“chain loading”。
顺便说一句,一旦你进入这个兔子洞,你可能会发现你不再需要 shell(......并重新考虑你的其他生活选择:-) 通过使用 execlineb
解释器以最小的开销启动服务非常有用而不是完全的外壳,即:
#!/bin/execlineb
...
envfile -I /etc/default/bla
envfile /etc/default/bla-bla
my_cmd
答案 26 :(得分:0)
我对此的贡献是对@的answer的扩展 user4040650 允许在 git repo 中轻松使用。它将尝试从当前目录中获取 .env 文件,或者如果它不存在,则从您所在的 git repo 中获取 .env 。如果您已经 cd 进入子目录然后不这样做会很有帮助不必提供 ../../.env 或诸如此类的东西。
我把它放在我的 .bashrc 中,所以我只需要在需要的地方调用 setenv
setenv() {
local env_path
if { [ -f .env ] && env_path='.env'; } || { env_path=$(git rev-parse --show-toplevel 2>/dev/null)/.env && [ -f "$env_path" ]; }; then
echo "sourcing $env_path"
set -o allexport
source "$env_path"
set +o allexport
else
echo "No env file found"
fi
}
答案 27 :(得分:0)
这是我的看法。我有以下要求:
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
受到Javier和其他一些评论的启发。
答案 28 :(得分: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
答案 29 :(得分: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')
答案 30 :(得分:0)
尝试这样的事情
for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done
答案 31 :(得分:0)
我找到的最短方法:
您的.env
文件:
VARIABLE_NAME="A_VALUE"
然后就
. ./.env && echo ${VARIABLE_NAME}
奖金:因为它很短,所以在package.json
文件中非常有用
"scripts": {
"echo:variable": ". ./.env && echo ${VARIABLE_NAME}"
}
答案 32 :(得分:0)
我在Mac上使用docker-compose和.env
文件,并想将.env
导入我的bash shell(以进行测试),这里的“最佳”答案是以下变量:
.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.
答案 33 :(得分:0)
首先,创建一个环境文件,该文件将具有如下所示环境的所有键值对,并根据您的喜好将其命名为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
答案 34 :(得分:0)
当我尝试在shell中重用Docker --env-file
时,我遇到了这个帖子。 Their format不兼容bash,但很简单:name=value
,没有引用,没有替换。他们还会忽略空白行和#
条评论。
我无法让它与posix兼容,但是这里应该可以在类似bash的shell中工作(在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)
不会处理上述文档中示例中的三个案例:
bash: export: `123qwe=bar': not a valid identifier
bash: export: `org.spring.config=something': not a valid identifier
FOO
)答案 35 :(得分:0)
我的.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
答案 36 :(得分:-1)
对于那些使用红宝石的人,我制作了一个名为dotenv_export
的实用工具。
dotenv_export
是一个小的实用程序命令,它读取.env
文件,并使用the ruby dotenv
implementation将其转换为export
语句。
# first install `dotenv_export`
gem install dotenv_export
然后,在您的.bash_profile
或要在其中加载环境变量的任何Shell环境中,执行以下命令:
eval "$(dotenv-export /path/to/.env)"