从环境文件中读取环境变量

Kur*_*eek 28 python docker

我想在本地环境中运行Python脚本,该脚本通常在Docker容器中运行.在docker-compose.yml指定了一个env_file看上去(部分)如下所示:

DB_ADDR=rethinkdb
DB_PORT=28015
DB_NAME=ipercron
Run Code Online (Sandbox Code Playgroud)

为了在本地运行,我将这些行转换为

os.environ['DB_ADDR'] = 'rethinkdb'
os.environ['DB_PORT'] = '28015'
os.environ['DB_NAME'] = 'ipercron'
Run Code Online (Sandbox Code Playgroud)

我可以编写我的解析器,但我想知道是否有任何现有的模块/工具可以从配置文件中读取环境变量?

Par*_*ser 99

我使用Python Dotenv 库。只需安装库pip install python-dotenv.env使用您的环境变量创建一个文件,然后在您的代码中导入环境变量,如下所示:

import os
from dotenv import load_dotenv

load_dotenv()

MY_ENV_VAR = os.getenv('MY_ENV_VAR')
Run Code Online (Sandbox Code Playgroud)

.env文件:

MY_ENV_VAR="This is my env var content."
Run Code Online (Sandbox Code Playgroud)

当我需要在我的 docker 系统之外测试代码并准备将它再次返回到 docker 时,我就是这样做的。

  • 对于像我这样的菜鸟来说,你的文件实际上需要命名为“.env”。它不会从“example.env”或类似的内容中读取。 (6认同)
  • 我还使用“dotenv”。当你来自 JS 后端环境时,有如此好的相似之处,学习曲线几乎是平坦的! (3认同)
  • 通常,在 .env 文件中,变量不需要引号。 (3认同)
  • 我想补充一点,根据文档“行可以以导出指令开头,这对其解释没有影响。”非常好。意味着您可以执行 `export MY_VAR="Env var"` 并与 bash 中的 `source .env` 兼容。也许将此信息添加到答案中很有用。我建议编辑,但队列已满 (3认同)
  • @alper 是的。如果您使用 load_dotenv(override=True)`,它只会覆盖 `.bashrc` 中已设置的环境变量,如 [GitHub 自述文件](https://github.com/theskumar/python-dotenv# 中所述)变量扩展)。 (2认同)

tab*_*ble 24

看看python-dotenv

  • 注意:pip包名为python-dotenv,不是dotenv。(不幸的是,还有一个完全无关的软件包,名为dotenv。) (4认同)
  • 不要使用它,它会大范围地换行,将两个变量合并为一个,依此类推。虽然可以阅读,但是“ dotenv set”根本不起作用。 (2认同)

rad*_*tek 12

这也适用于您:

env_vars = []
with open(env_file) as f:
    for line in f:
        if line.startswith('#') or not line.strip():
            continue
        # if 'export' not in line:
        #     continue
        # Remove leading `export `, if you have those
        # then, split name / value pair
        # key, value = line.replace('export ', '', 1).strip().split('=', 1)
        key, value = line.strip().split('=', 1)
        # os.environ[key] = value  # Load to local environ
        env_vars.append({'name': key, 'value': value}) # Save to a list

print(env_vars);
Run Code Online (Sandbox Code Playgroud)

在评论中,您会发现几种不同的方法来保存环境变量以及一些解析选项,即摆脱前导export关键字。另一种方法是使用python-dotenv库。干杯。

  • 将它们保存到“dict”中不是比保存到列表中更好吗?// +1 去掉前导 `export` 关键字 (2认同)

Mar*_*sad 10

Dewald Abrie 发布了一个很好的解决方案,这里有一个忽略隔断线的轻微修改 (\n)

def get_env_data_as_dict(path: str) -> dict:
    with open(path, 'r') as f:
       return dict(tuple(line.replace('\n', '').split('=')) for line
                in f.readlines() if not line.startswith('#'))

print(get_env_data_as_dict('../db.env'))
Run Code Online (Sandbox Code Playgroud)


Moi*_*dri 9

你可以用ConfigParser.示例可以在这里找到.

但是这个库期望你的key= value数据存在于某些数据库之下[heading].例如,像:

[mysqld]
user = mysql  # Key with values
pid-file = /var/run/mysqld/mysqld.pid
skip-external-locking
old_passwords = 1
skip-bdb      # Key without value
skip-innodb
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案的主要缺点是,如果添加了标头,则文件无法由具有“source <file>”的 shell 进行解析。 (5认同)

Gin*_*pin 9

如果您的系统/环境/工作流支持 POSIX shell 脚本,您可以创建一个包含这两个操作的脚本:

  1. 获取 .env 文件并将它们导出为环境变量
    • 使用set -a选项 where “创建或修改的每个变量或函数都被赋予导出属性并标记为导出到后续命令的环境”。
  2. 调用具有纯os.environ.get代码的Python 脚本/应用程序

这是一个示例 .env 文件(config.env):

TYPE=prod
PORT=5000
Run Code Online (Sandbox Code Playgroud)

这是 Python 代码(test.py):

import os

print(os.environ.get('TYPE'))
print(os.environ.get('PORT'))
Run Code Online (Sandbox Code Playgroud)

这是一个示例 bash 脚本(run.sh):

#!/usr/local/bin/bash

set -a
source config.env
set +a

python3 test.py
Run Code Online (Sandbox Code Playgroud)

这是一个示例运行:

$ tree
.
??? config.env
??? run.sh
??? test.py

$ echo $TYPE

$ echo $PORT

$ python3 test.py
None
None

$ ./run.sh 
prod
5000
Run Code Online (Sandbox Code Playgroud)

当您直接运行 Python 脚本 ( python3 test.py) 时,它使用.environ.get和不使用source.env 文件,它都会打印出 .env 文件None

但是,当您将其包装在首先将 .env 文件加载到环境变量中,然后运行 ​​Python 脚本(仍在使用.environ.get)的 shell 脚本中时,Python 脚本现在应该能够读取环境变量了。

其他流行的答案相比,这不需要任何外部 Python 库。

  • 我认为这是针对这个问题的真正的Linux解决方案。 (2认同)

Dew*_*rie 7

对于更紧凑的解决方案如何:

import os

with open('.docker-compose-env', 'r') as fh:
    vars_dict = dict(
        tuple(line.split('='))
        for line in fh.readlines() if not line.startswith('#')
    )

print(vars_dict)
os.environ.update(vars_dict)
Run Code Online (Sandbox Code Playgroud)

  • 好的。您的解决方案将 \n 添加到值中,因为它是行尾。稍微调整一下: `def get_env_data_as_dict(path: str) -> dict: with open(path, 'r') as f: return dict(tuple(line.replace('\n', '').split('= ')) for lin in f.readlines() if not line.startswith('#'))` (4认同)

h0t*_*1r3 6

仅使用python std

import re

envre = re.compile(r'''^([^\s=]+)=(?:[\s"']*)(.+?)(?:[\s"']*)$''')
result = {}
with open('/etc/os-release') as ins:
    for line in ins:
        match = envre.match(line)
        if match is not None:
            result[match.group(1)] = match.group(2)
Run Code Online (Sandbox Code Playgroud)