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,但同样的问题仍然适用

也许还有其他方法可以做到这一点,我只需要使用我传递的文件的环境变量作为脚本的参数。


当前回答

如果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"'

其他回答

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

如果env.txt像这样:

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

解释 -a等价于alleexport。换句话说,shell中的每个变量赋值都被导出到环境中(供多个子进程使用)。更多信息可以在Set内置文档中找到:

-a每个创建或修改的变量或函数都被赋予export属性,并标记为可导出到后续命令的环境。 使用“+”而不是“-”会关闭这些选项。还可以在调用shell时使用这些选项。当前选项集可以在$-中找到。

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,您将看到该命令产生的结果。

值中的空格

这里有很多很好的答案,但我发现它们都缺乏对值中空白的支持:

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)

这里的关键是使用声明-x并将line放在双引号中。我不知道为什么,但当你将循环代码重新格式化为多行时,它不会工作-我不是bash程序员,我只是狼吞虎咽地把这些放在一起,它对我来说仍然是魔法:)

如何保存变量:

printenv | sed 's/\([a-zA-Z0-9_]*\)=\(.*\)/export \1="\2"/' > myvariables.sh

如何装载它们

source myvariables.sh

-o allexport允许导出以下所有变量定义。+o allexport禁用此功能。

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