提问人:hugo19941994 提问时间:10/12/2013 最后编辑:Francisco Pugahugo19941994 更新时间:8/1/2023 访问量:956006
从键/值对文件设置环境变量
Set environment variables from file of key/value pairs
问:
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
也许还有其他方法可以做到这一点,我只需要使用我传递的文件的环境变量作为脚本的参数。
答:
您的方法的问题是 in 循环发生在子 shell 中,并且这些变量在当前 shell(while 循环的父 shell)中不可用。export
while
在文件本身中添加命令:export
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
然后,您需要使用以下命令在当前 shell 中的文件中获取源:
. ./conf/prac1
或
source ./conf/prac1
评论
< <(commands that generate output)
export
awk '{print "export " $0}' envfile
方便的命令,用于将导出预置到每行的开头
export
. ./conf/prac1
这可能会有所帮助:
export $(cat .env | xargs) && rails c
我使用它的原因是如果我想在我的 rails 控制台中测试东西。.env
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 系统上。
从这个答案中,你可以用这个自动检测操作系统:
export-env.sh
#!/bin/sh
## Usage:
## . ./export-env.sh ; $COMMAND
## . ./export-env.sh ; echo ${MINIENTREGA_FECHALIMITE}
unamestr=$(uname)
if [ "$unamestr" = 'Linux' ]; then
export $(grep -v '^#' .env | xargs -d '\n')
elif [ "$unamestr" = 'FreeBSD' ] || [ "$unamestr" = 'Darwin' ]; then
export $(grep -v '^#' .env | xargs -0)
fi
评论
eval $(cat .env) rails
tr -d '\r'
tr '\r' '\0'
export $(grep -v '^#' .env | tr '\r' '\0' | xargs -d '\n')
export $(grep -v '^#' .env | xargs -0)
xargs -d '\n'
您可以使用原始脚本来设置变量,但需要按以下方式调用它(使用独立的点):
. ./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
我对之前建议的解决方案有疑问:
- @anubhava的解决方案使编写 bash 友好的配置文件变得非常烦人,而且 - 您可能不想总是导出您的配置。
- @Silas Paul 解决方案中断时,您的变量具有空格或其他字符,这些字符在引号值中效果很好,但会弄得一团糟。
$()
这是我的解决方案,它仍然非常糟糕的 IMO - 并且没有解决 Silas 解决的“仅导出到一个子”问题(尽管您可能可以在子 shell 中运行它以限制范围):
source .conf-file
export $(cut -d= -f1 < .conf-file)
eval $(cat .env | sed 's/^/export /')
评论
eval $(cat .env | sed 's/^[^$]/export /')
cat .env | sed 's/^[^$]/export /'
A=foo\nB=bar\n
export =foo\nexport =bar\n
cat .env | sed '/^$/! s/^/export /'
cat
eval $(sed 's/^/export /' .env)
sed 's/^/export /' .env
-o allexport
允许导出以下所有变量定义。 禁用此功能。+o allexport
set -o allexport
source conf-file
set +o allexport
评论
set -o allexport && source conf-file && set +o allexport
SAVE=$(set +o | grep allexport) && set -o allexport && . .env; eval "$SAVE"
这将保存/恢复您的原始选项,无论它们是什么。
使用具有在没有正则表达式的情况下正确跳过注释的优点。set -o allexport
set +o
它本身以 bash 以后可以执行的格式输出所有当前选项。也很方便:它本身以人性化的格式输出您当前的所有选项。set -o
评论
exec env -i bash
eval
.env
改进 Silas Paul 的回答
在子 shell 上导出变量会使它们成为命令的本地变量。
(export $(cat .env | xargs) && rails c)
评论
(set -a; source dev.env; set +a; rails c)
该选项在此处的其他几个答案中提到,这是快捷方式。获取 .env 确实比遍历行和导出要好,因为它允许注释、空行,甚至命令生成的环境变量。我的 .bashrc 包括以下内容:allexport
set -a
# .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
}
评论
VAR=
如果由于其中一个变量包含包含空格的值而收到错误,您可以尝试重置 bash(内部字段分隔符)以让 bash 将结果解释为可执行文件的参数列表。IFS
\n
cat .env
env
例:
IFS=$'\n'; env $(cat .env) rails c
另请参阅:
这是另一种解决方案,它不运行 eval 或不需要 ruby:sed
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
加载到 systemd 单元文件中时特别有用。
我已经对 user4040650 的答案投了赞成票,因为它既简单又允许在文件中添加注释(即以 # 开头的行),这对我来说是非常可取的,因为可以添加解释变量的注释。只是在原始问题的上下文中重写。
如果脚本按指示调用: ,则 minientrega.sh 可能具有:minientrega.sh prac1
set -a # export all variables created next
source $1
set +a # stop exporting
# test that it works
echo "Ficheros: $MINIENTREGA_FICHEROS"
以下内容摘自集合文档:
这个内置函数非常复杂,值得拥有自己的部分。设置 允许您更改 shell 选项的值并将 位置参数,或显示 shell 的名称和值 变量。
set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument ...] set [+abefhkmnptuvxBCEHPT][+o 选项名称][参数...]
如果未提供任何选项或参数,则 set 将显示所有 shell 的名称和值 变量和函数,根据当前语言环境排序,在 可以重复用作设置或重置 当前设置的变量。只读变量无法重置。在 POSIX 中 模式下,仅列出 shell 变量。
提供选项时,它们设置或取消设置 shell 属性。 如果指定了选项,则具有以下含义:
-a 创建或修改的每个变量或函数都被赋予 export 属性,并标记为导出到 后续命令。
还有这个:
使用“+”而不是“-”会导致这些选项被关闭。这 还可以在调用 shell 时使用选项。当前集 的期权可以在 $- 中找到。
基于其他答案,这里有一种方法,可以仅导出文件中的行子集,包括带有空格的值,例如:PREFIX_ONE="a word"
set -a
. <(grep '^[ ]*PREFIX_' conf-file)
set +a
我的 .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
当我尝试在 shell 中重用 Docker 时,我遇到了这个线程。它们的格式与 bash 不兼容,但很简单:,没有引用,没有替换。它们还会忽略空行和注释。--env-file
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
)
set -a
. ./env.txt
set +a
如果像这样:env.txt
VAR1=1
VAR2=2
VAR3=3
...
解释 -a 等同于 allexport。换言之,shell 中的每个变量赋值都会导出到环境中(供多个子进程使用)。更多信息可以在 Set builtin 文档中找到:
-一个创建或修改的每个变量或函数都被赋予 export 属性,并标记为导出到后续命令的环境。
使用“+”而不是“-”会导致这些选项被关闭。这些选项也可以在调用 shell 时使用。当前的选项集可以在 $- 中找到。
评论
VAR2=$VAR1
.
简单:
- 抓取文件内容
- 删除任何空行(以防万一您分隔了一些内容)
- 删除任何评论(以防万一您添加了一些评论......
- 添加到所有行
export
eval
整个事情
eval $(cat .env | sed -e /^$/d -e /^#/d -e 's/^/export /')
另一种选择(您不必运行(感谢@Jaydeep)):eval
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
评论
source <( echo $(sed -E -n 's/[^#]+/ &/ p' <(echo "${2}" | tr -d '\r')) );
tr -d '\r'
值中的空格
这里有很多很好的答案,但我发现它们都缺乏对值中空格的支持:
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)
这里的关键是使用和将行放在双引号中。我不知道为什么,但是当您将循环代码重新格式化为多行时,它将不起作用 - 我不是bash程序员,我只是吞噬了这些,这对我来说仍然很神奇:)declare -x
评论
sed
-e
--expression
sed
-e /^$/d
-e /^#/d
'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
lorem ipsum
"lorem ipsum"
ENV_VAR="lorem ipsum"
sed
我的要求是:
- 没有前缀的简单 .env 文件(用于与 dotenv 兼容)
export
- 引号中的支持值:TEXT=“alpha bravo charlie”
- 支持以 # 为前缀和空行的注释
- 适用于 mac/BSD 和 linux/GNU
根据上述答案编译的完整工作版本:
set -o allexport
eval $(grep -v '^#' .env | sed 's/^/export /')
set +o allexport
评论
首先,创建一个环境文件,该文件将包含环境的所有键值对,如下所示,并按照您喜欢的任何名称命名(在我的情况下是它的)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
我在 Mac 上使用 docker-compose 和文件,并想将其导入到我的 bash shell(用于测试)中,这里的“最佳”答案是绊倒以下变量:.env
.env
.env
NODE_ARGS=--expose-gc --max_old_space_size=2048
溶液
所以我最终使用了 ,并将我的 env var defs 括在单引号中。eval
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.
我发现的最短方法:
您的文件:.env
VARIABLE_NAME="A_VALUE"
然后就
. ./.env && echo ${VARIABLE_NAME}
奖励:因为它是一个简短的单行代码,所以它在文件中非常有用package.json
"scripts": {
"echo:variable": ". ./.env && echo ${VARIABLE_NAME}"
}
注意:这种方式不会将变量导出到子进程,如果需要,请检查其他答案。
评论
VARIABLE_NAME="A_VALUE"
.
source
尝试这样的事情
for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done
我的 .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')
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
- 单行
评论
这是我的变体:
with_env() {
(set -a && . ./.env && "$@")
}
与以前的解决方案相比:
- 它不会泄漏作用域之外的变量(来自的值不会暴露给调用方)
.env
- 不 clobber 选项
set
- 返回已执行命令的退出代码
- 使用POSIX兼容
set -a
- 使用而不是避免 bashism
.
source
- 如果加载失败,则不调用命令
.env
with_env rails console
评论
set -a && . ./.env && "$@" && echo "your comand here"
我发现最有效的方法是:
export $(xargs < .env)
解释
当我们有这样的文件时:.env
key=val
foo=bar
运行将获得xargs < .env
key=val foo=bar
所以我们会得到一个,这正是我们所需要的!export key=val foo=bar
限度
- 它不处理值中包含空格的情况。env 等命令会生成此格式。– @Shardj
评论
这个处理 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
不太清楚为什么,或者我错过了什么,但在经历了大部分答案并失败了之后。我意识到使用这个.env文件:
MY_VAR="hello there!"
MY_OTHER_VAR=123
我可以简单地这样做:
source .env
echo $MY_VAR
输出:Hello there!
似乎在 Ubuntu linux 中工作得很好。
评论
这是我对此的看法。我有以下要求:
- 忽略注释行
- 允许值中的空格
- 允许空行
- 能够在默认为 .env 时传递自定义 env 文件
- 允许导出以及内联运行命令
- 如果 env 文件不存在,则退出
source_env() {
env=${1:-.env}
[ ! -f "${env}" ] && { echo "Env file ${env} doesn't exist"; return 1; }
eval $(sed -e '/^\s*$/d' -e '/^\s*#/d' -e 's/=/="/' -e 's/$/"/' -e 's/^/export /' "${env}")
}
将函数保存到.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
受到哈维尔和其他一些评论的启发。
修改自 @Dan Kowalczyk
我把它放进去.~/.bashrc
set -a
. ./.env >/dev/null 2>&1
set +a
与 Oh-my-Zsh 的 dotenv 插件交叉兼容非常好。(有 Oh-my-bash,但它没有 dotenv 插件。
对于那些使用红宝石的人,我制作了一个名为 dotenv_export
的小型实用宝石。
用法
dotenv_export
是一个小型实用程序命令,它读取文件并使用 Ruby Dotenv
实现将其转换为语句。.env
export
# first install `dotenv_export`
gem install dotenv_export
然后,在 或要加载环境变量的任何 shell 环境中,执行以下命令:.bash_profile
eval "$(dotenv-export /path/to/.env)"
评论
我用这个:
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'
然后将 equal 替换为 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
然后最终采购所有这些。
它应该适用于具有所有特殊字符的几乎所有情况。
如何保存变量:
printenv | sed 's/\([a-zA-Z0-9_]*\)=\(.*\)/export \1="\2"/' > myvariables.sh
我如何加载它们
source myvariables.sh
如果支持该选项,则可以使用换行符或转义字符,例如 或(参见 env):env
-S
\n
\t
env -S "$(cat .env)" command
.env
文件示例:
KEY="value with space\nnewline\ttab\tand
multiple
lines"
测试:
env -S "$(cat .env)" sh -c 'echo "$KEY"'
问题在于它要求文件具有正确的 bash 语法,并且某些特殊字符会破坏它:、、、、等。因此,在某些情况下,您可以source
=
"
'
<
>
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
direnv
用户请注意:它有一个辅助功能,请在您的文件中使用它:dotenv
.envrc
[ -f ".env" ] && dotenv ".env"
评论
sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/\ *=\ */=/g")
如果您打算将脚本的最后一个命令作为脚本的最后一个命令,则可以使用解释器进行其他选择。这是脚本最后一行的样子:exec
execlineb
#!/bin/sh
...
exec envfile -I /etc/default/bla envfile /etc/default/bla-bla my_cmd
envfile ...
是来自套件的命令,它们依赖于“链加载”。
顺便说一句,一旦你进入这个兔子洞,你可能会发现你不再需要外壳了(......并重新考虑您的其他生活选择:-)通过使用解释器而不是 shell,它对于以最小的开销启动服务非常有用,即:execline
execlineb
#!/bin/execlineb
...
envfile -I /etc/default/bla
envfile /etc/default/bla-bla
my_cmd
使用 shdotenv
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 脚本。
- POSIX shell(破折号、bash、ksh、zsh 等)
- awk(gawk、nawk、mawk、busybox awk)
评论
source
我对此的贡献是扩展了@的答案 user4040650 以允许在 Git 存储库中轻松使用。它将尝试从当前目录获取 .env 文件,或者如果不存在,则从您所在的 git 存储库中获取 .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
}
符合 POSIX 的解决方案(不依赖于 bash)
正如其他人所指出的,在这里使用 for/while 循环的问题在于变量在 shell 及其子 shell 之间不共享。然而,我们可以做的是使用 args/stdin/stdout 在 shell 之间传递文本。
当我们获取脚本时,在子 shell 中设置环境变量将无济于事
变量不会传播回去 - 但我们知道我们可以发送文本。这个文本也可以是代码,我们可以在当前的 shell 中使用 .eval
如果我们生成用于设置所有环境变量的代码,然后对结果进行评估,会怎么样?
create_exports_script() {
echo "$1" | while read line; do
echo "export $line"
done
}
file_contents=$(cat "./conf/myconf.env")
eval $(create_exports_script "$file_contents")
bash 中的这种函数式元编程可以非常灵活。您也可以通过这种方式生成 bash/sh 以外的其他语言。
我的版本:
我打印文件,删除注释行、空行,并从“=”符号拆分键/值。然后我只应用导出命令。
此解决方案的优点是文件可以在值中包含特殊字符,例如管道、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
sh -ac '. conf-file; yourcommand'
开关导出所有变量,以便它们可供程序使用。-a
与较长的版本不同,使用可确保导出的值不会永久污染当前环境。它只为在子 shell 中运行的程序获取和导出变量。set -a; . conf-file; set +a; yourcommand
sh
export
就是答案!
自己进行互动练习
由于 shell 是交互式的,因此您可以尝试几乎所有内联内容!
$ mkdir conf && printf 'MINIENTREGA_%s="%s"\n' FECHALIMITE 2011-03-31 FICHEROS \
"informe.txt programa.c" DESTINO ./destino/entrega-prac1 >conf/prac1
$ set -- prac1 # set "prac1" as positional argument "$1" see `help set`
$ while read -r line; do export $line; done <"conf/$1"
bash: export: `programa.c"': not a valid identifier
$ while read -r line; do LANG=C export "$line"; done <"conf/$1"
$ echo "$MINIENTREGA_FICHEROS"
"informe.txt programa.c"
注意双引号!
source
别名.
$ set -- prac1
$ . "conf/$1"
$ echo "$MINIENTREGA_FICHEROS"
informe.txt programa.c
还行!那么现在呢?export
export
命令告诉 shell 将他的变量导出到环境...因此,您必须先导出脚本变量,然后才能将它们用于任何子进程(如 、 ,甚至是另一个脚本。ruby
python
perl
shell
清理以前的操作以进行进一步的演示
$ declare +x MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ unset MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
因此,在交互式 shell 中,尝试此操作的最简单方法是运行另一个 shell:
$ set -- prac1
$ . "conf/$1"
$ sh -c 'echo "$MINIENTREGA_FICHEROS"'
这只是打印一个空行,但如果你导出变量:
$ export MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ sh -c 'echo "$MINIENTREGA_FICHEROS"'
informe.txt programa.c
用于导出变量的示例 shell 包装器
最小的包装器,没有安全问题(在采购可由其他用户编辑的脚本时要小心!!
#!/bin/sh
while IFS== read -r varname _;do
case $varname in
*[!A-Za-z0-9_]* | '' ) ;;
* ) export $varname ;;
esac
done <conf/$1
. conf/$1
busybox sh -c 'set | grep MINIENTREGA'
使用 as 参数运行,应产生:prac1
MINIENTREGA_DESTINO='./destino/entrega-prac1'
MINIENTREGA_FECHALIMITE='2011-03-31'
MINIENTREGA_FICHEROS='informe.txt programa.c'
在罚款中
获取配置文件与声明变量相同。
导出变量是指示 shell 在全局环境中为任何子进程共享变量。
这两个操作可以按任何顺序无动于衷地完成。唯一的要求是在尝试运行任何子进程之前完成这两个操作。
您甚至可以通过在配置文件中导出来同时执行这两个操作,例如:
export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"
您甚至可以在一次操作中编写以下内容:
export MINIENTREGA_FICHEROS="informe.txt programa.c" \
MINIENTREGA_FECHALIMITE="2011-03-31" MINIENTREGA_DESTINO="./destino/entrega-prac1"
现在有一些抨击
bash 确实提供了很多用于变量操作的工具
使用变量名称:nameref
#!/bin/bash
buildMiniEntragaVar() {
local -n _MiniEntragaVar="MINIENTREGA_$1"
export "MINIENTREGA_$1"
_MiniEntragaVar="$2"
}
buildMiniEntragaVar FECHALIMITE "2011-03-31"
buildMiniEntragaVar FICHEROS "informe.txt programa.c"
buildMiniEntragaVar DESTINO "./destino/entrega-prac1"
然后,使用 bash,您可以使用以下命令显示任何变量的属性和内容:declare -p
declare -p MINIENTREGA_FECHALIMITE MINIENTREGA_DESTINO MINIENTREGA_FICHEROS
declare -x MINIENTREGA_FECHALIMITE="2011-03-31"
declare -x MINIENTREGA_DESTINO="./destino/entrega-prac1"
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"
按变量名称前缀匹配进行扩展:
这是一个很好的工具!从手册页:
${!prefix*} ${!prefix@} Names matching prefix. Expands to the names of variables whose names begin with prefix, separated by the first character of the IFS special variable. When @ is used and the expansion appears within double quotes, each variable name expands to a separate word.
在上一个示例的实践中,使用可以写成:declare -p
declare -p ${!MINIENTREGA_*}
declare -x MINIENTREGA_DESTINO="./destino/entrega-prac1"
declare -x MINIENTREGA_FECHALIMITE="2011-03-31"
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"
当然,这可以用于以前定义的变量:export
MINIENTREGA_FECHALIMITE="2011-03-31"
MINIENTREGA_FICHEROS="informe.txt programa.c"
MINIENTREGA_DESTINO="./destino/entrega-prac1"
export "${!MINIENTREGA_@}"
取消导出变量:
不幸的是,没有命令。为此,您可以使用 export 命令或 sign 的标志,而不是 for 命令:unexport
-n
+
-
declare
export -n MINIENTREGA_DESTINO
declare +x MINIENTREGA_FICHEROS
这两个命令都将取消设置变量的导出 flog。
导出数组或关联数组:
由于 bash 数组和关联数组是 bashism,因此它们无法在 POSIX 环境中导出:
export -a myavar='(1 2)'
export -A myAvar='([foo]=1 [bar]=2)'
echo ${myavar[1]} ${myAvar[bar]}
2 2
declare -p "${!my@}"
declare -Ax myAvar=([foo]="1" [bar]="2" )
declare -ax myavar=([0]="1" [1]="2")
但
bash -c 'echo ${myavar[1]} ${myAvar[bar]}'
这只是打印一个空行!!当旗帜在场时!x
为此,一种解决方法是使用带有标志的 --rcfile:-i
bash --rcfile <(declare -p "${!my@}") --noediting -ic 'echo ${myavar[1]} ${myAvar[bar]}'
2 2
bash --rcfile <(declare -p "${!my@}") --noediting -i file.sh
或者,如果使用交互式可能会导致问题,则可以连接脚本:
bash -c "$(declare -p "${!my@}");"'echo ${myavar[1]} ${myAvar[bar]}'
2 2
或
bash -c "$(declare -p "${!my@}");file.sh"
甚至
bash -c "$(declare -p "${!my@}");. file.sh"
如果文件不可执行,例如示例:
bash -c "$(declare -p "${!my@}");. <(echo 'echo ${myavar[1]} ${myAvar[bar]}')"
2 2
我以一个基于+方法的解决方案结束。这里的主要思想是防止覆盖现有变量。allexport
source
function load_env_file() {
local FILE_PATH="${1}"
local EXISTENT_VARS=$(declare)
set -o allexport
source "${FILE_PATH}"
set +o allexport
# errors are supressed as "declare" returns also readonly vars which are not overridable
eval "${EXISTENT_VARS}" 2> /dev/null || true
}
# Usage example:
load_env_file "path/to/.env"
export $(grep -v '^#' envfilename | xargs -L 1 -d '\r' -d '\r\n')
这在 CentOS 上就像一个魅力;当你遇到被追加到加载的变量的问题时。此外,它还负责注释和空格。\r
如果你愿意,我的看法是保持全局环境变量空间不变,我认为这是可取的。
创建一个脚本,如下所示:
# !/bin/sh
set -o allexport
source $1
set +o allexport
shift
exec $@
然后像这样使用:
dotenv env-file my-binary
一种方法是即时创建一个文件,该文件位于每行的开头,将其放在子 shell 中,然后执行您的命令:zsh
export
$ cat env.db
VAR=" value = with!! special chars #"
$ ( . =(sed 's/^[^#]/export \0/' < env.db) && echo $VAR)
value = with!! special chars #
$ echo $VAR
$
我构建此脚本以动态方式获取 env vars。
我之所以使用这个脚本,是因为我不想记住我在项目中使用的每个变量的名称,也不想将导出命令存储在历史记录中,也不希望将完整文件导出到 git 中。.env
#!/bin/sh
filename=".secret"
secret_var () {
# Parametter 1 : Environnement vars anme
bash -c 'read -p '$1=' -s voila && echo '$1'"=${voila}" > '$filename''
export `cat .secret`
rm $filename
echo ''
}
public_var () {
# Parametter 1 : Environnement vars anme
bash -c 'read -p '$1=' voila && echo '$1'"=${voila}" > '$filename''
export `cat .secret`
rm $filename
}
if [ -e $filename ]
then
echo "A file named '.secret' already exist. Remove it or edit this script."
else
public_var MY_USER_VAR
secret_var MY_PASS_VAR
fi
它非常易于使用:
# To add var MY_VAR_NAME to the env
public_var MY_VAR_NAME
# To add var MY_VAR_NAME secretly into the env
secret_var MY_VAR_NAME
例:
callmarl@LAPTOP ~ % source set_env.sh
MY_USER_VAR=myusername
MY_PASS_VAR=
callmarl@LAPTOP ~ % env
MY_USER_VAR=myusername
MY_PASS_VAR=mysecretpass
当然,如果您想要存储值,则可以直接使用。export
public_var
很抱歉添加另一个答案,但由于它很简单并且在许多情况下都有效,请尝试:
export $(< ~/my/.env)
一些注意事项:
- “.env”文件应具有“LF”行尾序列。
- 避免在环境变量中使用动态值,例如
variable1=$variable2@$variable3
- 避免在环境变量 vavlue 中使用引号 (),例如
"
variable="value"
这是最好和最简短的答案
source .env && export $(cut -d= -f1 < .env)
评论