简体   繁体   English

如何告诉POpen使用/设置某些环境变量?

[英]How do I tell POpen to use/set certain environment variables?

I'm using Python 3.7 and Django. 我正在使用Python 3.7和Django。 I use the below to run a command I would normally run in the shell ... 我用下面的命令运行我通常会在外壳中运行的命令...

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

his dies with the error 他死于错误

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

What I'm trying to figure out is how to give my Python environment access to the normal environment variables I have access to, or figure out a way to set them before I run my Python command. 我试图找出的是如何让我的Python环境访问我可以访问的普通环境变量,或者找到一种在运行Python命令之前设置它们的方法。 Normally "node" is easily found when I check as myself 通常,当我自己检查时,很容易找到“节点”

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

But I don't know how to tell Python to use the same PATH that I have access to. 但是我不知道如何告诉Python使用我可以访问的相同PATH。

If we refer to Popen's documentation , we can see three relevant arguments: 如果我们参考Popen的文档 ,我们可以看到三个相关的参数:

  1. cwd str or path -like object, that's the current working directory cwd strcwd path的对象,即当前工作目录
  2. env mapping (let's say a dict ), that's the environment mapping passed to the called program env映射(比如说dict ),这就是传递给调用程序的环境映射
  3. shell flag, whether you wrap the program inside of a shell or not shell标志,是否将程序包装在shell中

Let's review each solution. 让我们回顾每个解决方案。


If you can afford it, just use cwd="where is node" , for instance, if node is in /usr/local/bin , you can just use cwd=/usr/local/bin or cwd=os.path.join(USR_LOCAL, 'bin') for example. 如果负担得起,只需使用cwd="where is node" ,例如,如果node/usr/local/bin ,则可以仅使用cwd=/usr/local/bincwd=os.path.join(USR_LOCAL, 'bin')例如。 But, everything will be created in this folder, which might not be what you wish for (logs, assumptions on the current working directory). 但是,所有内容都将在此文件夹中创建,而这可能不是您想要的 (日志,当前工作目录上的假设)。


Now, for the environment: 现在,针对环境:

If env is not None, it must be a mapping that defines the environment variables for the new process; 如果env不为None,则它必须是为新进程定义环境变量的映射。 these are used instead of the default behavior of inheriting the current process' environment. 这些被用来代替继承当前进程环境的默认行为。 It is passed directly to Popen. 它直接传递给Popen。

You can just copy your current environment through os.environ and add something in the PATH like this: 您可以通过os.environ复制当前环境,然后在PATH添加如下内容:

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

Then pass this new_env mapping and there you are! 然后通过此new_env映射,您就可以了!


If you really want to rely on shell, you can, but here's the platform-details: 如果您真的想依靠shell,可以,但是这里是平台详细信息:

POSIX-platforms POSIX平台

On POSIX with shell=True, the shell defaults to /bin/sh. 在shell = True的POSIX上,shell默认为/ bin / sh。 If args is a string, the string specifies the command to execute through the shell. 如果args是字符串,则该字符串指定要通过外壳执行的命令。 This means that the string must be formatted exactly as it would be when typed at the shell prompt. 这意味着字符串的格式必须与在shell提示符下键入时的格式完全相同。 This includes, for example, quoting or backslash escaping filenames with spaces in them. 例如,这包括在文件名中使用引号或反斜杠转义。 If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. 如果args是序列,则第一项指定命令字符串,任何其他项都将被视为shell本身的其他参数。 That is to say, Popen does the equivalent of: Popen(['/bin/sh', '-c', args[0], args[1], ...]) 也就是说,Popen等效于: Popen(['/bin/sh', '-c', args[0], args[1], ...])

Windows platforms Windows平台

On Windows with shell=True, the COMSPEC environment variable specifies the default shell. 在shell = True的Windows上,COMSPEC环境变量指定默认的Shell。 The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (eg dir or copy). 在Windows上唯一需要指定shell = True的时间是将要执行的命令内置到shell中(例如dir或copy)。 You do not need shell=True to run a batch file or console-based executable. 您不需要shell = True即可运行批处理文件或基于控制台的可执行文件。

You can use something like PATH=whatever and use your whole shell-fu directly, but caveats are: security considerations . 您可以使用类似PATH=whatever类的PATH=whatever并直接使用整个shell-fu,但需要注意的是: 安全注意事项。


Bonus solution 奖金解决方案

Just re-define PATH before calling your Python process. 只需在调用Python进程之前重新定义PATH。 If you're using Django, you're either using: 如果您使用的是Django,则可以使用:

  1. The development server 开发服务器
  2. A production-grade server 生产级服务器

In both cases, all you have to do is to re-define the environment of the parent process, for a production-grade server such as Gunicorn, this is possible and there is documentation to do it. 在这两种情况下,您要做的就是重新定义父进程的环境,对于Gunicorn这样的生产级服务器,这是可能的,并且有文档可以做到这一点。 For a development server, do it at your own shell level (but warning! You might have to document such a behavior or tell anyone using your software you're assuming node is in the path which is… most of the time fair). 对于开发服务器,请在您自己的外壳程序级别上执行此操作(但请注意!您可能必须记录这种行为,或者告诉任何使用您的软件的人,您认为node在…通常是公平的路径中)。

os.environ.copy() is best for what you're looking for. os.environ.copy()最适合您要寻找的东西。

import subprocess, os
my_env = os.environ.copy()
out = Popen([settings.SELENIUM_RUNNER_CMD, file_path], stderr=STDOUT, stdout=PIPE, env=my_env)
t = out.communicate()[0], out.returncode

And that should be it! 就是这样!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM