如何在转义特殊字符的同时在python中扩展环境变量?

时间:2016-03-09 23:51:20

标签: python json bash escaping

在主机上,我有一个环境变量,其值中包含引号,如:

export VALUE_WITH_QUOTE_FROM_OS='quote"value'

当我回应bash时,它很好

#echo $VALUE_WITH_QUOTE_FROM_OS
quote"value

我有一个以下的json字符串:

json_str = '{"key":"${VALUE_WITH_QUOTE_FROM_OS}"}'

然后我想在进一步处理之前在python脚本中扩展环境变量,类似这样

json_str = os.path.expandvars(json_str)
json_dict = json.loads(json_str)

但是,这种扩展会破坏json语法,因为json_str已经变成

'{"key":"quote"value"}' (<== bad unescaped quote in the value)

而不是

'{"key":"quote\"value"}' 

无论如何我可以在扩展值时通知os.path.expandvars()以逃避双引号?如果没有,我应该如何扩展环境变量,以便可以转义双引号。

注1 环境变量的值是一个安全令牌,因此我必须保持双引号不变。

注意2 当前的json接口已经确定并且可以按原样使用。这个json_str传递给我,因此我应该而且必须只扩展json字符串中$ {}表示的环境变量,不允许进行其他修改。

注3 此json_str非常大,具有复杂,动态,嵌套的结构,并且由无法访问主机os环境变量的多个客户端使用。虽然我可以首先加载json_str,遍历字典来解析环境变量,然后将dict转发回json_str,然后发送给所有客户端,我认为与处理它相比效率较低就像一个字符串。

感谢。

2 个答案:

答案 0 :(得分:2)

我当然不保证这会带来os.path的可移植性,但这应该主要适用于我认为使用posix的系统:

import re
import os
import json

regex = re.compile(r'\$(\w+|\{[^}]*\})')
json_str = '{"key":"${FOO}"}'
def os_expandvar(match):
    v = match.group(1)
    if v.startswith('{') and v.endswith('}'):
        v = v[1:-1]
    return json.dumps(os.environ.get(v, ''))[1:-1]
print(regex.sub(os_expandvar, json_str))

正则表达式(以及一般的实现思路)借鉴了posixpath模块中os.path.expandvars的实现。我删除了很多复杂性来简化答案,但如果你发现需要它,你可以把它重新放回去。

这应该处理替换字符串为$FOO${FOO}的情况,这在posix系统中是典型的。

此处还有其他选项...根据您提供的示例,您可以先解码json ,然后展开所有值。根据json的格式,您可能需要一个递归函数来完成工作:

# untested
def json_expandvars(o):
    if isinstance(o, dict):
       return {json_expandvars(k): json_expandvars(v) for k, v in o.items()}
    elif isinstance(o, list):
       return [json_expandvars(v) for v in o]
    elif isinstance(o, basestring):
       return os.path.expandvars(o)
    else:
       return o

json_dict = json_expandvars(json.loads(json_str))

答案 1 :(得分:0)

os.path.expandvars无法知道结果必须是有效的JSON字符串,并且引号已转义。

相反,在将JSON解码为字典后,将环境变量扩展为

json_dict = json.loads(json_str);
json_dict['key'] = os.path.expandvars(json_dict['key']);