破损的 Popen("source the_script.sh")
等同于 Popen(["source the_script.sh"])
,试图无法成功启动程序 'source the_script.sh'
,因为找不到它,所以会出现 "No such file or directory"
错误。
破损的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所说,在子进程中执行
source
并不能影响父进程的环境,因此不是很有用。
基于
os.environ.update(env)
的方法会因为
the_script.sh
执行了
unset
而失败。可以调用
os.environ.clear()
来重置环境:
import os
from pprint import pprint
from subprocess import check_output
os.environ['a'] = 'a'*100
output = check_output("source the_script.sh; env -0", shell=True,
executable="/bin/bash")
os.environ.clear()
os.environ.update(line.partition('=')[::2] for line in output.split('\0'))
pprint(dict(os.environ))
它使用了@unutbu建议的env -0
和.split('\0')
为了支持os.environb
中的任意字节,可以使用json
模块(假设我们使用修复了"json.dumps not parsable by json.loads" issue问题的Python版本):
为了避免通过管道传递环境变量,Python代码可以更改为在子进程环境中调用自身,例如:
import os
import sys
from pipes import quote
from pprint import pprint
if "--child" in sys.argv:
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))
ShellManager
(许可证MIT)是否适合您? - tonypopen
函数,那么它的主要参数是要执行的shell脚本。您可以在该shell脚本中执行解决问题所需的任何操作,例如. /path/to/env.sh ; binary
。先加载环境脚本,然后用分号隔开,再运行二进制文件。如果环境脚本可能会失败,或者可能找不到等情况,我们可以使用&&
代替分号,以避免在这种情况下尝试运行程序。 - Kaz