首页 > 解决方案 > 如何告诉 POpen 使用/设置某些环境变量?

问题描述

我正在使用 Python 3.7 和 Django。我使用下面的命令来运行我通常会在 shell 中运行的命令......

out = Popen([settings.SELENIUM_RUNNER_CMD, file_path], stderr=STDOUT, stdout=PIPE)
t = out.communicate()[0], out.returncode

他死于错误

b'env: node: No such file or directory\n'

我想弄清楚的是如何让我的 Python 环境访问我可以访问的正常环境变量,或者在我运行我的 Python 命令之前找出一种设置它们的方法。通常,当我以自己的身份检查时,很容易找到“节点”

davea$ which node
/usr/local/bin/node

但我不知道如何告诉 Python 使用我可以访问的相同 PATH。

标签: pythondjangopython-3.xenvironment-variablespopen

解决方案


如果我们参考Popen 的文档,我们可以看到三个相关的论点:

  1. cwd stror path-like 对象,即当前工作目录
  2. env映射(比方说 a dict),这是传递给被调用程序的环境映射
  3. shell标志,是否将程序包装在外壳中

让我们回顾一下每个解决方案。


如果你负担得起,就使用cwd="where is node",例如,如果node是 in /usr/local/bin,你可以使用cwd=/usr/local/binor cwd=os.path.join(USR_LOCAL, 'bin')。但是,所有内容都将在此文件夹中创建,这可能不是您想要的(日志、当前工作目录的假设)。


现在,对于环境:

如果 env 不是 None,它必须是定义新进程的环境变量的映射;这些用于代替继承当前进程环境的默认行为。它直接传递给 Popen。

您可以复制当前环境os.environ并添加PATH如下内容:

new_env = os.environ.copy()
new_env['PATH'] = '{}:/usr/local/bin'.format(new_env['PATH'])

然后通过这个new_env映射,你就在那里!


如果你真的想依赖 shell,你可以,但这里是平台详细信息:

POSIX 平台

在 shell=True 的 POSIX 上,shell 默认为 /bin/sh。如果 args 是字符串,则该字符串指定要通过 shell 执行的命令。这意味着字符串的格式必须与在 shell 提示符下键入时的格式完全相同。这包括,例如,引用或反斜杠转义文件名,其中包含空格。如果 args 是一个序列,则第一项指定命令字符串,任何附加项都将被视为 shell 本身的附加参数。也就是说,Popen 相当于:Popen(['/bin/sh', '-c', args[0], args[1], ...])

视窗平台

在 shell=True 的 Windows 上,COMSPEC 环境变量指定默认 shell。唯一需要在 Windows 上指定 shell=True 的情况是当您希望执行的命令内置到 shell 中时(例如 dir 或 copy)。您不需要 shell=True 来运行批处理文件或基于控制台的可执行文件。

您可以使用类似的东西PATH=whatever并直接使用您的整个 shell-fu,但需要注意的是:安全考虑


奖金解决方案

只需在调用 Python 进程之前重新定义 PATH 即可。如果您使用的是 Django,您可以使用:

  1. 开发服务器
  2. 生产级服务器

在这两种情况下,您所要做的就是重新定义父进程的环境,对于像 Gunicorn 这样的生产级服务器,这是可能的,并且有文档可以做到这一点。对于开发服务器,请在您自己的 shell 级别执行此操作(但警告!您可能必须记录此类行为或告诉任何使用您的软件的人,您假设node处于……大多数情况下是公平的路径)。


推荐阅读