标签归档:popen

如何使用子流程Popen Python

问题:如何使用子流程Popen Python

由于os.popen被subprocess.popen取代,我想知道如何转换

os.popen('swfdump /tmp/filename.swf/ -d')

到subprocess.popen()

我试过了:

subprocess.Popen("swfdump /tmp/filename.swf -d")
subprocess.Popen("swfdump %s -d" % (filename))  # NOTE: filename is a variable
                                                # containing /tmp/filename.swf

但是我想我没有正确地写出来。任何帮助,将不胜感激。谢谢

Since os.popen is being replaced by subprocess.popen, I was wondering how would I convert

os.popen('swfdump /tmp/filename.swf/ -d')

to subprocess.popen()

I tried:

subprocess.Popen("swfdump /tmp/filename.swf -d")
subprocess.Popen("swfdump %s -d" % (filename))  # NOTE: filename is a variable
                                                # containing /tmp/filename.swf

But I guess I’m not properly writing this out. Any help would be appreciated. Thanks


回答 0

subprocess.Popen 接受参数列表:

from subprocess import Popen, PIPE

process = Popen(['swfdump', '/tmp/filename.swf', '-d'], stdout=PIPE, stderr=PIPE)
stdout, stderr = process.communicate()

该文档中甚至有一部分专门用于帮助用户从迁移os.popensubprocess

subprocess.Popen takes a list of arguments:

from subprocess import Popen, PIPE

process = Popen(['swfdump', '/tmp/filename.swf', '-d'], stdout=PIPE, stderr=PIPE)
stdout, stderr = process.communicate()

There’s even a section of the documentation devoted to helping users migrate from os.popen to subprocess.


回答 1

使用sh,它将使事情变得容易得多:

import sh
print sh.swfdump("/tmp/filename.swf", "-d")

Use sh, it’ll make things a lot easier:

import sh
print sh.swfdump("/tmp/filename.swf", "-d")

回答 2

以最简单的方式使用子流程!

import subprocess
cmd = 'pip install numpy'.split()  #replace with your command
subprocess.call(cmd)

Using Subprocess in easiest way!!

import subprocess
cmd = 'pip install numpy'.split()  #replace with your command
subprocess.call(cmd)

如何为Popen指定工作目录

问题:如何为Popen指定工作目录

有没有一种方法可以在Python的目录中指定命令的运行目录subprocess.Popen()

例如:

Popen('c:\mytool\tool.exe', workingdir='d:\test\local')

我的Python脚本位于 C:\programs\python

是否可以C:\mytool\tool.exe在目录中运行D:\test\local

如何设置子流程的工作目录?

Is there a way to specify the running directory of command in Python’s subprocess.Popen()?

For example:

Popen('c:\mytool\tool.exe', workingdir='d:\test\local')

My Python script is located in C:\programs\python

Is is possible to run C:\mytool\tool.exe in the directory D:\test\local?

How do I set the working directory for a sub-process?


回答 0

subprocess.Popen 接受一个cwd参数来设置当前工作目录;您还需要转义反斜杠('d:\\test\\local'),或使用,r'd:\test\local'以便Python不会将反斜杠解释为转义序列。按照您编写的方式,\t零件将被翻译为tab

因此,您的新行应如下所示:

subprocess.Popen(r'c:\mytool\tool.exe', cwd=r'd:\test\local')

要将Python脚本路径用作cwd,import os并使用以下命令定义cwd:

os.path.dirname(os.path.realpath(__file__)) 

subprocess.Popen takes a cwd argument to set the Current Working Directory; you’ll also want to escape your backslashes ('d:\\test\\local'), or use r'd:\test\local' so that the backslashes aren’t interpreted as escape sequences by Python. The way you have it written, the \t part will be translated to a tab.

So, your new line should look like:

subprocess.Popen(r'c:\mytool\tool.exe', cwd=r'd:\test\local')

To use your Python script path as cwd, import os and define cwd using this:

os.path.dirname(os.path.realpath(__file__)) 

子流程Popen和call有什么区别(我该如何使用它们)?

问题:子流程Popen和call有什么区别(我该如何使用它们)?

我想从Python调用一个外部程序。我已经使用过Popen()并且call()做到了。

两者有什么区别?

我的特定目标是从Python运行以下命令。我不确定重定向如何工作。

./my_script.sh > output

我阅读了文档,并说它call()是便利功能或快捷功能。我们使用call()代替会失去任何功能Popen()吗?

I want to call an external program from Python. I have used both Popen() and call() to do that.

What’s the difference between the two?

My specific goal is to run the following command from Python. I am not sure how redirects work.

./my_script.sh > output

I read the documentation and it says that call() is a convenience function or a shortcut function. Do we lose any power by using call() instead of Popen()?


回答 0

重定向有两种方法。两者都适用于subprocess.Popensubprocess.call

  1. 设置关键字参数shell = Trueexecutable = /path/to/the/shell并在那里指定命令。

  2. 由于您只是将输出重定向到文件,因此请设置关键字参数

    stdout = an_open_writeable_file_object

    对象指向output文件的位置。

subprocess.Popensubprocess.call

Popen不会阻塞,允许您在进程运行时与之进行交互,或者继续进行Python程序中的其他操作。调用Popen返回一个Popen对象。

call 阻止。它支持与Popen构造函数相同的所有参数,因此您仍可以设置进程的输出,环境变量等,脚本将等待程序完成,并call返回表示进程退出状态的代码。

returncode = call(*args, **kwargs) 

与通话基本相同

returncode = Popen(*args, **kwargs).wait()

call只是一种便利功能。它在CPython的实现是在subprocess.py

def call(*popenargs, timeout=None, **kwargs):
    """Run command with arguments.  Wait for command to complete or
    timeout, then return the returncode attribute.

    The arguments are the same as for the Popen constructor.  Example:

    retcode = call(["ls", "-l"])
    """
    with Popen(*popenargs, **kwargs) as p:
        try:
            return p.wait(timeout=timeout)
        except:
            p.kill()
            p.wait()
            raise

如您所见,它周围是薄薄的包装纸Popen

There are two ways to do the redirect. Both apply to either subprocess.Popen or subprocess.call.

  1. Set the keyword argument shell = True or executable = /path/to/the/shell and specify the command just as you have it there.

  2. Since you’re just redirecting the output to a file, set the keyword argument

    stdout = an_open_writeable_file_object
    

    where the object points to the output file.

subprocess.Popen is more general than subprocess.call.

Popen doesn’t block, allowing you to interact with the process while it’s running, or continue with other things in your Python program. The call to Popen returns a Popen object.

call does block. While it supports all the same arguments as the Popen constructor, so you can still set the process’ output, environmental variables, etc., your script waits for the program to complete, and call returns a code representing the process’ exit status.

returncode = call(*args, **kwargs) 

is basically the same as calling

returncode = Popen(*args, **kwargs).wait()

call is just a convenience function. It’s implementation in CPython is in subprocess.py:

def call(*popenargs, timeout=None, **kwargs):
    """Run command with arguments.  Wait for command to complete or
    timeout, then return the returncode attribute.

    The arguments are the same as for the Popen constructor.  Example:

    retcode = call(["ls", "-l"])
    """
    with Popen(*popenargs, **kwargs) as p:
        try:
            return p.wait(timeout=timeout)
        except:
            p.kill()
            p.wait()
            raise

As you can see, it’s a thin wrapper around Popen.


回答 1

另一个答案很完整,但这是一个经验法则:

  • call 正在阻止:

    call('notepad.exe')
    print('hello')  # only executed when notepad is closed
    
  • Popen 是非阻塞的:

    Popen('notepad.exe')
    print('hello')  # immediately executed
    

The other answer is very complete, but here is a rule of thumb:

  • call is blocking:

    call('notepad.exe')
    print('hello')  # only executed when notepad is closed
    
  • Popen is non-blocking:

    Popen('notepad.exe')
    print('hello')  # immediately executed
    

具有修改后环境的Python子进程/ Popen

问题:具有修改后环境的Python子进程/ Popen

我认为在环境稍有修改的情况下运行外部命令是很常见的情况。这就是我倾向于这样做的方式:

import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

我感觉到有更好的方法了。看起来还好吗?

I believe that running an external command with a slightly modified environment is a very common case. That’s how I tend to do it:

import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

I’ve got a gut feeling that there’s a better way; does it look alright?


回答 0

我认为os.environ.copy()如果您不打算为当前进程修改os.environ会更好:

import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

I think os.environ.copy() is better if you don’t intend to modify the os.environ for the current process:

import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

回答 1

这取决于问题所在。如果要克隆和修改环境,一种解决方案可能是:

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))

但这在某种程度上取决于被替换的变量是有效的python标识符,它们通常是有效的(您遇到频率不是字母数字+下划线的环境变量名称还是以数字开头的变量的频率是多少?)。

否则,您将可以编写如下内容:

subprocess.Popen(my_command, env=dict(os.environ, 
                                      **{"Not valid python name":"value"}))

在非常奇怪的情况下(您多久在环境变量名称中使用控制代码或非ASCII字符?),bytes您甚至(在python3上)都无法使用该结构的环境键。

正如您所看到的,此处使用的技术(尤其是第一种)对环境键的好处通常是有效的python标识符,并且也预先知道(在编码时),第二种方法存在问题。如果不是这种情况,您可能应该寻找另一种方法

That depends on what the issue is. If it’s to clone and modify the environment one solution could be:

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))

But that somewhat depends on that the replaced variables are valid python identifiers, which they most often are (how often do you run into environment variable names that are not alphanumeric+underscore or variables that starts with a number?).

Otherwise you’ll could write something like:

subprocess.Popen(my_command, env=dict(os.environ, 
                                      **{"Not valid python name":"value"}))

In the very odd case (how often do you use control codes or non-ascii characters in environment variable names?) that the keys of the environment are bytes you can’t (on python3) even use that construct.

As you can see the techniques (especially the first) used here benefits on the keys of the environment normally is valid python identifiers, and also known in advance (at coding time), the second approach has issues. In cases where that isn’t the case you should probably look for another approach.


回答 2

您可以使用它,my_env.get("PATH", '')而不是my_env["PATH"]PATH某种方式在原始环境中未定义,但除此之外,它看起来还不错。

you might use my_env.get("PATH", '') instead of my_env["PATH"] in case PATH somehow not defined in the original environment, but other than that it looks fine.


回答 3

使用Python 3.5,您可以通过以下方式实现:

import os
import subprocess

my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}

subprocess.Popen(my_command, env=my_env)

在这里,我们得到的副本os.environ并覆盖了PATH值。

PEP 448(其他拆包概述)使之成为可能。

另一个例子。如果您具有默认环境(例如os.environ),并且想要使用默认值覆盖字典,则可以这样表示:

my_env = {**os.environ, **dict_with_env_variables}

With Python 3.5 you could do it this way:

import os
import subprocess

my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}

subprocess.Popen(my_command, env=my_env)

Here we end up with a copy of os.environ and overridden PATH value.

It was made possible by PEP 448 (Additional Unpacking Generalizations).

Another example. If you have a default environment (i.e. os.environ), and a dict you want to override defaults with, you can express it like this:

my_env = {**os.environ, **dict_with_env_variables}

回答 4

要临时设置环境变量而不必复制os.envrion对象等,我可以这样做:

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)

To temporarily set an environment variable without having to copy the os.envrion object etc, I do this:

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)

回答 5

env参数接受字典。您可以简单地使用os.environ,在其中添加键(如果需要,可以将其添加到dict的副本中)(用作键)Popen

The env parameter accepts a dictionary. You can simply take os.environ, add a key (your desired variable) (to a copy of the dict if you must) to that and use it as a parameter to Popen.


回答 6

我知道已经回答了一段时间,但是有些人可能想知道一些有关在环境变量中使用PYTHONPATH而不是PATH的知识。我已经概述了使用cronjobs运行python脚本的说明,该说明以另一种方式(在此处找到)处理修改后的环境。认为这对像我这样需要的人仅比此答案所提供的要多。

I know this has been answered for some time, but there are some points that some may want to know about using PYTHONPATH instead of PATH in their environment variable. I have outlined an explanation of running python scripts with cronjobs that deals with the modified environment in a different way (found here). Thought it would be of some good for those who, like me, needed just a bit more than this answer provided.


回答 7

在某些情况下,您可能只希望传递子流程所需的环境变量,但是我认为您通常具有正确的想法(这也是我的做法)。

In certain circumstances you may want to only pass down the environment variables your subprocess needs, but I think you’ve got the right idea in general (that’s how I do it too).