我有一个看起来像这样的脚本:
export foo=/tmp/foo
export bar=/tmp/bar
每次我构建时都运行'source init_env'(其中init_env是上面的脚本)来设置一些变量。
为了在Python中完成同样的操作,我运行了这个代码,
reg = re.compile('export (?P<name>\w+)(\=(?P<value>.+))*')
for line in open(file):
m = reg.match(line)
if m:
name = m.group('name')
value = ''
if m.group('value'):
value = m.group('value')
os.putenv(name, value)
但有人决定在init_env
文件中添加如下行:
export PATH="/foo/bar:/bar/foo:$PATH"
显然我的Python脚本崩溃了。我可以修改Python脚本来处理这一行,但是当某人提出要在init_env
文件中使用的新功能时,它就会稍后中断。
问题是,是否有一种简单的方法可以运行Bash命令并让它修改我的os.environ
?
答案 0 :(得分:93)
您的方法存在的问题是您正在尝试解释bash脚本。首先,您只是尝试解释导出语句。然后你会注意到人们正在使用变量扩展。后来人们会将条件放在他们的文件中,或者处理替换。最后,您将拥有一个完整的bash脚本解释器,其中包含大量错误。不要那样做。
让Bash为您解释文件,然后收集结果。
你可以这样做:
#! /usr/bin/env python
import os
import pprint
import shlex
import subprocess
command = shlex.split("env -i bash -c 'source init_env && env'")
proc = subprocess.Popen(command, stdout = subprocess.PIPE)
for line in proc.stdout:
(key, _, value) = line.partition("=")
os.environ[key] = value
proc.communicate()
pprint.pprint(dict(os.environ))
确保在bash无法source init_env
失败或bash本身无法执行,或者子进程无法执行bash或任何其他错误的情况下处理错误。
命令行开头的env -i
创建一个干净的环境。这意味着您只能从init_env
获取环境变量。如果您想要继承的系统环境,则省略env -i
。
阅读subprocess上的文档了解更多详情。
注意:这只会捕获使用export
语句设置的变量,因为env
仅打印导出的变量。
享受。
请注意,Python documentation表示如果您想操纵环境,则应直接操作os.environ
,而不是使用os.putenv()
。我认为这是一个错误,但我离题了。
答案 1 :(得分:25)
使用泡菜:
import os, pickle
# For clarity, I moved this string out of the command
source = 'source init_env'
dump = '/usr/bin/python -c "import os,pickle;print pickle.dumps(os.environ)"'
penv = os.popen('%s && %s' %(source,dump))
env = pickle.loads(penv.read())
os.environ = env
更新:
这使用json,subprocess,并显式使用/ bin / bash(对于ubuntu支持):
import os, subprocess as sp, json
source = 'source init_env'
dump = '/usr/bin/python -c "import os, json;print json.dumps(dict(os.environ))"'
pipe = sp.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=sp.PIPE)
env = json.loads(pipe.stdout.read())
os.environ = env
答案 2 :(得分:19)
使用包装器脚本源init_env
,然后使用修改后的环境运行Python脚本,而不是让Python脚本使用bash脚本,这样会更简单,更优雅。
#!/bin/bash
source init_env
/run/python/script.py
答案 3 :(得分:3)
更新了@ lesmana对Python 3的回答。请注意import os, subprocess
if os.path.isfile("init_env"):
command = 'env -i sh -c "source init_env && env"'
for line in subprocess.getoutput(command).split("\n"):
key, value = line.split("=")
os.environ[key]= value
的使用,它可以防止设置/重置无关的环境变量(由于缺少对多行env变量的处理,可能会错误)。
Service
答案 4 :(得分:3)
示例包装@Brian在函数中的优秀答案:
import json
import subprocess
# returns a dictionary of the environment variables resulting from sourcing a file
def env_from_sourcing(file_to_source_path, include_unexported_variables=False):
source = '%ssource %s' % ("set -a && " if include_unexported_variables else "", file_to_source_path)
dump = '/usr/bin/python -c "import os, json; print json.dumps(dict(os.environ))"'
pipe = subprocess.Popen(['/bin/bash', '-c', '%s && %s' % (source, dump)], stdout=subprocess.PIPE)
return json.loads(pipe.stdout.read())
我使用此实用程序功能使用include_unexported_variables=True
读取aws凭据和docker .env文件。
答案 5 :(得分:-10)
execfile('filename')
应该这样做