如何使用python脚本替换要解析的yaml文件中的环境变量值

新手上路,请多包涵

我需要在需要用脚本解析的 yaml 文件中使用环境变量“PATH”。

这是我在终端上设置的环境变量:

 $ echo $PATH
/Users/abc/Downloads/tbwork

这是我的 sample.yml:

 ---
Top: ${PATH}/my.txt
Vars:
- a
- b

当我用我的脚本解析这个 yaml 文件时,我没有看到 PATH 变量的实际值。

这是我的脚本:

 import yaml
import os
import sys

stream = open("sample.yml", "r")
docs = yaml.load_all(stream)
for doc in docs:
    for k,v in doc.items():
        print k, "->", v
    print "\n",

输出:

 Top -> ${PATH}/my.txt
Vars -> ['a', 'b']

预期输出是:

 Top -> /Users/abc/Downloads/tbwork/my.txt
Vars -> ['a', 'b']

如果我做错了,有人可以帮我找出正确的方法吗?

原文由 npatel 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

PY-yaml 库默认不解析环境变量。您需要定义一个隐式解析器,它将找到定义环境变量的正则表达式并执行一个函数来解析它。

您可以通过 yaml.add_implicit_resolveryaml.add_constructor 。在下面的代码中,您定义了一个将匹配 YAML 值中的 ${ env variable } 的解析器,并调用函数 path_constructor 来查找环境变量。

 import yaml
import re
import os

path_matcher = re.compile(r'\$\{([^}^{]+)\}')
def path_constructor(loader, node):
  ''' Extract the matched value, expand env variable, and replace the match '''
  value = node.value
  match = path_matcher.match(value)
  env_var = match.group()[2:-1]
  return os.environ.get(env_var) + value[match.end():]

yaml.add_implicit_resolver('!path', path_matcher)
yaml.add_constructor('!path', path_constructor)

data = """
env: ${VAR}/file.txt
other: file.txt
"""

if __name__ == '__main__':
  p = yaml.load(data, Loader=yaml.FullLoader)
  print(os.environ.get('VAR')) ## /home/abc
  print(p['env']) ## /home/abc/file.txt

警告: 如果您不是指定环境变量(或任何其他不受信任的输入)的人,请不要运行此程序,因为截至 2020 年 7 月,FullLoader 存在远程代码执行漏洞。

原文由 dmchk 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您不想修改全局/默认的 yaml Loader,这是一个使用新 Loader 类的替代版本。

更重要的是,它正确地替换了不仅仅是环境变量的内插字符串,例如 path/to/${SOME_VAR}/and/${NEXT_VAR}/foo/bar

         path_matcher = re.compile(r'.*\$\{([^}^{]+)\}.*')
        def path_constructor(loader, node):
            return os.path.expandvars(node.value)

        class EnvVarLoader(yaml.SafeLoader):
            pass

        EnvVarLoader.add_implicit_resolver('!path', path_matcher, None)
        EnvVarLoader.add_constructor('!path', path_constructor)

        with open(configPath) as f:
            c = yaml.load(f, Loader=EnvVarLoader)

原文由 kolis 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题