使用subprocess.Popen()在python脚本中设置PYTHONPATH失败

PYTHONPATH setting inside python script using subprocess.Popen() fails

本问题已经有最佳答案,请猛点这里访问。

如果自定义模块不在sys.path变量的任何目录中,下面的代码允许我动态地标识和加载该模块。

1
2
import sys
sys.path.append("/lib")

但是,这给了我一个错误

1
2
import subprocess
x = subprocess.Popen(["export","PYTHONPATH=/lib"], stdout=subprocess.PIPE)

不仅如此,甚至简单的linux/unix变量声明设置也会在subprocess.popen()中失败。

1
2
import subprocess
x = subprocess.Popen("x=y", stdout=subprocess.PIPE)

我想检查子进程,因为我试图通过os.system()、os.popen()等设置pythonpath,但变量没有设置(可能是在子进程shell中设置的)。


这里发生了一些事情,可能会让你有点困惑。一件事是,给popen的任何指令都将在子进程中执行,不会影响主进程。您只能通过管道或从中检索结果。

首先对第二个用例进行注释,其中使用字符串作为参数。从文档中可以看到:

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
stdout=None, stderr=None, preexec_fn=None, close_fds=True,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0, restore_signals=True,
start_new_session=False, pass_fds=())

args should be a sequence of program arguments or else a single
string. By default, the program to execute is the first item in args
if args is a sequence. If args is a string, the interpretation is
platform-dependent and described below. See the shell and executable
arguments for additional differences from the default behavior. Unless
otherwise stated, it is recommended to pass args as a sequence.

On POSIX, if args is a string, the string is interpreted as the name
or path of the program to execute. However, this can only be done if
not passing arguments to the program.

因此,在第二种情况下,您试图执行一个文件或程序x=y,但它不起作用。

即使您像在第一个用例中那样使用list,您也必须知道,这并不等同于向bash shell传递代码。如果需要,可以使用shell=true作为关键字参数,但这还有文档指出的其他问题。但您的代码将以shell=true执行。

如果您的唯一目的是设置环境变量,那么您应该考虑使用将环境变量映射到值的os.environ变量(如@cdarke所示)。


试试这个:

1
2
3
4
>>> subprocess.call(["export foo=bar && echo foo=$foo"], shell=True)
foo=bar
0
>>>