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

其他回答

我对之前建议的解决方案有问题:

@anubhava的解决方案使得编写bash友好的配置文件非常烦人,而且-你可能不想总是导出你的配置。 @Silas Paul解决方案中断时,你的变量有空格或其他字符,在引号值中工作得很好,但$()使混乱。

以下是我的解决方案,在我看来仍然很糟糕——并且不能解决Silas提出的“只导出到一个孩子”的问题(尽管你可能可以在子shell中运行它来限制范围):

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

简单:

获取文件的内容 删除任何空行(以防你分开一些东西) 删除任何注释(以防你添加了一些…) 将export添加到所有行 对整个事件进行评估

eval (cat .env美元| sed - e / ^ $ / d - e / ^ # / d - e ' s / ^ /出口/ ')

另一个选择(你不必运行eval(感谢@Jaydeep)):

export $(cat .env | sed -e /^$/d -e /^#/d | xargs)

最后,如果你想让你的生活真的很简单,把这个添加到你的~/.bash_profile:

函数source_envfile() {export $(cat $1 | sed -e /^$/d -e /^#/d | xargs);}

(请务必重新加载bash设置!!~ /来源。bash_profile或. .只要新建一个标签/窗口,问题就解决了),你这样叫它:source_envfile .env

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

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

这个函数处理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

在其他答案的基础上,这里是一种只导出文件中一行的子集的方法,包括像PREFIX_ONE="a word"这样的空格值:

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