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

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


当前回答

出口是答案。

交互式exercices

由于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
$ 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"

注意双引号!

源代码。

$ set -- prac1
$ . "conf/$1"
$ echo "$MINIENTREGA_FICHEROS"
informe.txt programa.c

好的,现在是关于出口的问题

导出命令告诉shell将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"
$ bash -c 'declare -p MINIENTREGA_FICHEROS'
bash: line 1: declare: MINIENTREGA_FICHEROS: not found

$ export MINIENTREGA_FECHALIMITE MINIENTREGA_FICHEROS MINIENTREGA_DESTINO
$ bash -c 'declare -p MINIENTREGA_FICHEROS'
declare -x MINIENTREGA_FICHEROS="informe.txt programa.c"

用于导出变量的示例外壳包装器

最小的包装,没有安全问题(当其他用户编辑脚本时要注意!!)。

#!/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'

以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"

其他回答

对于那些使用ruby的人,我制作了一个名为dotenv_export的小型实用工具gem。

使用

Dotenv_export是一个小的实用程序命令,它读取。env文件,并使用ruby dotenv实现将其转换为导出语句。

# first install `dotenv_export`
gem install dotenv_export

然后,在你的.bash_profile中,或者任何你想要加载环境变量的shell环境中,执行以下命令:

eval "$(dotenv-export /path/to/.env)"

我给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"

以下摘录自设定的文档:

This builtin is so complicated that it deserves its own section. set allows you to change the values of shell options and set the positional parameters, or to display the names and values of shell variables. set [--abefhkmnptuvxBCEHPT] [-o option-name] [argument …] set [+abefhkmnptuvxBCEHPT] [+o option-name] [argument …] If no options or arguments are supplied, set displays the names and values of all shell variables and functions, sorted according to the current locale, in a format that may be reused as input for setting or resetting the currently-set variables. Read-only variables cannot be reset. In POSIX mode, only shell variables are listed. When options are supplied, they set or unset shell attributes. Options, if specified, have the following meanings: -a Each variable or function that is created or modified is given the export attribute and marked for export to the environment of subsequent commands.

还有这个:

使用“+”而不是“-”会关闭这些选项。的 选项也可以在调用shell时使用。当前集 的选项可在$-中找到。

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

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

试试这样的方法

for line in `cat your_env_file`; do if [[ $line != \#* ]];then export $line; fi;done

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