损坏的Popen("source the_script.sh") 相当于Popen(["source the_script.sh"]) 尝试启动'source the_script.sh' 程序失败。它找不到它,因此 "No such file or directory" 错误。
Broken Popen("source the_script.sh", shell=True) 失败,因为 source 是 bash 内置命令(在 bash 中键入 help source),但默认 shell 是 /bin/sh,它不理解它(/bin/sh 使用 .)。假设the_script.sh 中可能有其他 bash-ism,它应该使用 bash 运行:
foo = Popen("source the_script.sh", shell=True, executable="/bin/bash")
作为@IfLoop said,在子进程中执行source并不是很有用,因为它不会影响父进程的环境。
如果the_script.sh 对某些变量执行unset,则基于os.environ.update(env) 的方法会失败。可以调用os.environ.clear() 重置环境:
#!/usr/bin/env python2
import os
from pprint import pprint
from subprocess import check_output
os.environ['a'] = 'a'*100
# POSIX: name shall not contain '=', value doesn't contain '\0'
output = check_output("source the_script.sh; env -0", shell=True,
executable="/bin/bash")
# replace env
os.environ.clear()
os.environ.update(line.partition('=')[::2] for line in output.split('\0'))
pprint(dict(os.environ)) #NOTE: only `export`ed envvars here
它使用env -0 and .split('\0') suggested by @unutbu
为了支持os.environb 中的任意字节,可以使用json 模块(假设我们使用固定"json.dumps not parsable by json.loads" issue 的Python 版本):
为避免通过管道传递环境,可以将 Python 代码更改为在子进程环境中调用自身,例如:
#!/usr/bin/env python2
import os
import sys
from pipes import quote
from pprint import pprint
if "--child" in sys.argv: # executed in the child environment
pprint(dict(os.environ))
else:
python, script = quote(sys.executable), quote(sys.argv[0])
os.execl("/bin/bash", "/bin/bash", "-c",
"source the_script.sh; %s %s --child" % (python, script))