我对各种答案不满意,需要更复杂一点来处理更多边缘情况,例如任意数量的反斜杠和 ${} 样式变量,但不想支付 bash 评估的成本。这是我基于正则表达式的解决方案:
#!/bin/python
import re
import os
def expandvars(data,environ=os.environ):
out = ""
regex = r'''
( (?:.*?(?<!\\)) # Match non-variable ending in non-slash
(?:\\\\)* ) # Match 0 or even number of backslash
(?:$|\$ (?: (\w+)|\{(\w+)\} ) ) # Match variable or END
'''
for m in re.finditer(regex, data, re.VERBOSE|re.DOTALL):
this = re.sub(r'\\(.)',lambda x: x.group(1),m.group(1))
v = m.group(2) if m.group(2) else m.group(3)
if v and v in environ:
this += environ[v]
out += this
return out
# Replace with os.environ as desired
envars = { "foo":"bar", "baz":"$Baz" }
tests = { r"foo": r"foo",
r"$foo": r"bar",
r"$$": r"$$", # This could be considered a bug
r"$$foo": r"$bar", # This could be considered a bug
r"\n$foo\r": r"nbarr", # This could be considered a bug
r"$bar": r"",
r"$baz": r"$Baz",
r"bar$foo": r"barbar",
r"$foo$foo": r"barbar",
r"$foobar": r"",
r"$foo bar": r"bar bar",
r"$foo-Bar": r"bar-Bar",
r"$foo_Bar": r"",
r"${foo}bar": r"barbar",
r"baz${foo}bar": r"bazbarbar",
r"foo\$baz": r"foo$baz",
r"foo\\$baz": r"foo\$Baz",
r"\$baz": r"$baz",
r"\\$foo": r"\bar",
r"\\\$foo": r"\$foo",
r"\\\\$foo": r"\\bar",
r"\\\\\$foo": r"\\$foo" }
for t,v in tests.iteritems():
g = expandvars(t,envars)
if v != g:
print "%s -> '%s' != '%s'"%(t,g,v)
print "\n\n"