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

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


当前回答

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

如果env.txt像这样:

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

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

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

其他回答

出口是答案。

交互式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"

如何保存变量:

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

如何装载它们

source myvariables.sh
set -a
. ./env.txt
set +a

如果env.txt像这样:

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

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

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

我构建这个脚本动态地源env vars。

我使用这个脚本是因为我不想记住我在项目中使用的每个变量的名称,我不希望导出命令被存储在历史记录中或完整的.env文件导出到git。

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

首先,创建一个环境文件,其中包含如下所示环境的所有键-值对,并将其命名为任何您喜欢的名称,在我的示例中为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