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

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


当前回答

posix兼容的解决方案(不依赖于bash)

正如其他人所注意到的,在这里使用for/while循环的问题是,变量在shell及其子shell之间不共享。然而,我们能做的是使用args/stdin/stdout在shell之间传递文本。

在subshell中设置环境变量在我们获取脚本源代码时是没有帮助的

变量不会向上传播,但我们知道可以将文本发送回去。这个文本也可以是代码,我们可以用eval在当前shell中求值。

如果我们生成用于设置所有环境变量的代码,然后对结果进行计算呢?

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以外的其他语言。

其他回答

修改自@Dan Kowalczyk

我把它放在~/.bashrc中。

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

与Oh-my-Zsh的dotenv插件非常好的交叉兼容。(有Oh-my-bash,但它没有dotenv插件。)

问题与您的方法是导出在while循环发生在一个子shell,这些变量将不可用在当前shell(父shell的while循环)。

在文件本身中添加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

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

如何保存变量:

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

如何装载它们

source myvariables.sh

最佳和简单的解决方案 环境文件env.txt

fruit=apple
vegetable=carrot

代码文件Code .sh

#!/bin/bash

source <filepath>/env.txt
echo $fruit
echo $vegetable