首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

subprocess

2.4版本中的新功能。

subprocess模块允许你产生新的进程,连接到他们的输入/输出/错误管道,并获得他们的返回代码。该模块旨在替换几个较旧的模块和功能:

代码语言:javascript
复制
os.system
os.spawn*
os.popen*
popen2.*
commands.*

有关如何使用此模块替换旧功能的信息可以在子流程替换部分找到。

1.使用子流程模块

推荐子程序的推荐方法是使用以下便利功能。对于更高级的用例,如果这些用例不能满足您的需求,请使用基础Popen接口。

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

运行args描述的命令。等待命令完成,然后返回returncode属性。

上面显示的参数仅仅是最常用的参数,在下面的常用参数中进行了描述(因此缩写签名中的略带奇数的记号)。完整的函数签名与Popen构造函数的签名相同- 该函数将所有提供的参数直接传递到该接口。

例子:

代码语言:javascript
复制
>>> subprocess.call(["ls", "-l"])
0

>>> subprocess.call("exit 1", shell=True)
1

警告

使用shell=True可能是安全隐患。有关详细信息,请参阅常用参数下的警告。

注意

不要使用stdout=PIPEstderr=PIPE使用此功能,因为它可能会基于子进程输出量导致死锁。在需要管道时使用Popencommunicate()方法。

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

带参数运行命令。等待命令完成。如果返回码为零,则返回,否则提升CalledProcessError。该CalledProcessError对象将在returncode属性中具有返回码。

上面显示的参数仅仅是最常用的参数,在下面的常用参数中进行了描述(因此缩写签名中的略带奇数的记号)。完整的函数签名与Popen构造函数的签名相同- 该函数将所有提供的参数直接传递到该接口。

例子:

代码语言:javascript
复制
>>> subprocess.check_call(["ls", "-l"])
0

>>> subprocess.check_call("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

2.5版本中的新功能。

警告

使用shell=True可能是安全隐患。有关详细信息,请参阅常用参数下的警告。

注意

不要使用stdout=PIPEstderr=PIPE使用此功能,因为它可能会基于子进程输出量导致死锁。在需要管道时使用Popencommunicate()方法。

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

使用参数运行命令并将其输出作为字节字符串返回。

如果返回代码不为零,则会引发一次CalledProcessError。该CalledProcessError对象将在returncode属性中具有返回码,并在属性中包含任何输出output

上面显示的参数仅仅是最常用的参数,在下面的常用参数中进行了描述(因此缩写签名中的略带奇数的记号)。完整的函数签名与Popen构造函数的签名基本相同,只是stdout不允许在内部使用。所有其他提供的参数都直接传递给Popen构造函数。

例子:

代码语言:javascript
复制
>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'

>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

要在结果中捕获标准错误,请使用stderr=subprocess.STDOUT

代码语言:javascript
复制
>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
'ls: non_existent_file: No such file or directory\n'

2.7版本的新功能。

警告

使用shell=True可能是安全隐患。有关详细信息,请参阅常用参数下的警告。

注意

请勿使用stderr=PIPE此功能,因为可能会因子进程错误量而导致死锁。当你需要一个stderr管道时使用Popencommunicate()方法。

subprocess.PIPE

特殊值,可用作标准输入标准输出标准错误参数,Popen并指示应打开标准流的管道。

subprocess.STDOUT

可以用作stderr参数的特殊值,Popen并指示标准错误应该与标准输出进入相同的句柄。

exception subprocess.CalledProcessError

当进程运行check_call()check_output()返回非零退出状态时引发异常。

returncode

退出子进程的状态。

cmd

用于产生子进程的命令。

output

子进程的输出,如果这个异常被引发check_output()。否则,None

1.1。常用参数

为了支持各种各样的用例,Popen构造函数(和便利函数)接受大量的可选参数。对于大多数典型的用例,这些参数中的很多可以安全地保留其默认值。最常见的论据是:

所有调用都需要args,并且应该是一个字符串或一系列程序参数。提供一系列参数通常是首选的,因为它允许模块处理任何所需的参数转义和引用(例如允许文件名中的空格)。如果传递一个字符串,则shell必须是True(见下文),否则字符串必须简单地命名要执行的程序而不指定任何参数。

stdinstdoutstderr分别指定执行的程序的标准输入,标准输出和标准错误文件句柄。有效值是PIPE一个现有的文件描述符(一个正整数),一个现有的文件对象,和NonePIPE表示应该创建一个新的管道给孩子。使用默认设置None,不会发生重定向; 孩子的文件句柄将从父类继承。此外,stderr可以是STDOUT,这表示应该将stderr数据从子进程捕获到与stdout相同的文件句柄中。

stdoutstderr是管道并且universal_newlines时True则所有行结束都将转换'\n'为对通用换行符 'U'模式参数所述open()

如果shellTrue,则指定的命令将通过shell执行。如果您主要将Python用于其在大多数系统shell中提供的增强控制流并且仍希望方便地访问其他shell功能,如shell管道,文件名通配符,环境变量扩展以及扩展~到用户的主目录。但是请注意,Python本身提供了很多贝壳般的功能实现(特别是globfnmatchos.walk()os.path.expandvars()os.path.expanduser(),和shutil)。

警告

执行包含来自不可信源的未经处理的输入的shell命令会使程序容易受到shell注入的攻击,这是一个严重的安全漏洞,可导致任意命令执行。出于这个原因,使用shell=True强烈反对在命令字符串是从外部输入的情况下构造:

代码语言:javascript
复制
>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

shell=False禁用所有基于shell的功能,但不受此漏洞的影响; 请参阅Popen构造函数文档中的注释以获取有用的提示shell=False

在使用时shell=Truepipes.quote()可用于正确地转义要用于构造shell命令的字符串中的空白和shell元字符。

这些选项以及所有其他选项在Popen构造函数文档中有更详细的描述。

1.2。Popen构造函数

该模块中的基础过程创建和管理由Popen该类处理。它提供了很大的灵活性,以便开发人员能够处理不属于便利功能范围的不常见情况。

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

在新过程中执行子程序。在Unix上,类使用os.execvp()类行为来执行子程序。在Windows上,该类使用Windows CreateProcess()功能。参数Popen如下。

参数应该是一系列程序参数或者一个字符串。默认情况下,如果args是一个序列,则要执行的程序是args中的第一个项目。如果args是一个字符串,则解释是依赖于平台的,并在下面进行描述。查看shell可执行参数以获取与默认行为的其他差异。除非另有说明,否则建议按照顺序传递参数

在Unix上,如果args是一个字符串,则该字符串将被解释为要执行的程序的名称或路径。但是,只有在不向程序传递参数的情况下才能完成此操作。

注意

shlex.split()在确定参数的正确标记时,尤其是在复杂情况下可能有用:

代码语言:javascript
复制
>>> import shlex, subprocess
>>> command_line = raw_input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print args
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!

请特别注意,shell中由空白分隔的选项(例如-input)和参数(如eggs.txt)将放在单独的列表元素中,而在shell中使用时需要引用或反斜杠转义的参数(例如包含空格或上面显示的echo命令的文件名)是单个列表元素。

在Windows上,如果args是序列,则它将按照在Windows 上将参数序列转换为字符串中所述的方式转换为字符串。这是因为底层CreateProcess()在字符串上运行。

所述shell参数(默认为False)指定是否使用壳作为要执行的程序。如果shellTrue,建议将args作为字符串传递,而不是作为序列传递。

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

代码语言:javascript
复制
Popen(['/bin/sh', '-c', args[0], args[1], ...])

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

警告

shell=True如果与不可信输入结合使用,传递可能会带来安全隐患。有关详细信息,请参阅常用参数下的警告。

如果给定,bufsize与内建的open()函数的相应参数具有相同的含义:0意味着无缓冲,1意味着行缓冲,任何其他正值意味着使用(近似)该大小的缓冲区。负bufsize意味着使用系统默认值,通常意味着完全缓冲。bufsize的默认值是0(无缓冲)。

注意

如果遇到性能问题,建议您尝试通过将bufsize设置为-1或足够大的正值(如4096)来启用缓冲。

可执行文件参数指定的替代程序来执行。这是很少需要的。何时shell=False可执行文件会将程序替换为由args指定的执行程序。但是,原始参数仍然传递给程序。大多数程序会将由args指定的程序视为命令名称,这可能与实际执行的程序不同。在Unix上,args名称成为ps等实用程序中可执行文件的显示名称。如果shell=True在Unix上可执行参数指定了默认的替换shell /bin/sh

stdinstdoutstderr分别指定执行的程序的标准输入,标准输出和标准错误文件句柄。有效值是PIPE一个现有的文件描述符(一个正整数),一个现有的文件对象,和NonePIPE表示应该创建一个新的管道给孩子。使用默认设置None,不会发生重定向; 孩子的文件句柄将从父类继承。此外,stderr可以是STDOUT,这表示应该将stderr数据从子进程捕获到与stdout相同的文件句柄中。

如果将preexec_fn设置为可调用对象,则该对象将在子进程执行前被调用。(仅适用于Unix)

如果close_fds为true,则将执行子进程之前的所有文件描述符01并且2将被关闭。(仅适用于Unix)。或者,在Windows上,如果close_fds为true,那么子进程将不会继承任何句柄。请注意,在Windows上,您不能将close_fds设置为true,并通过设置stdinstdoutstderr来重定向标准句柄。

如果cwd不是None,那么在执行之前,该子目前的目录将被更改为cwd。请注意,搜索可执行文件时不考虑此目录,因此您无法指定程序相对于cwd的路径。

如果env不是None,它必须是一个为新进程定义环境变量的映射; 这些用来代替继承当前进程的环境,这是默认行为。

注意

如果指定,env必须提供程序执行所需的任何变量。在Windows上,为了运行并行程序集,指定的env 必须包含有效的SystemRoot

如果universal_newlinesTrue,文件对象标准输出标准错误被打开,如文本文件通用换行模式。行可以通过任何'\n'Unix终止约定,'\r'旧的Macintosh约定或'\r\n'Windows约定来终止。所有这些外部表示都被'\n'Python程序看到。

注意

此功能仅在Python使用通用换行支持(默认)构建时才可用。此外,文件对象的换行符属性stdoutstdinstderr不会通过communications()方法更新。

如果给出,startupinfo将是一个STARTUPINFO对象,它被传递给底层CreateProcess函数。创造性标志,如果给出,可以是CREATE_NEW_CONSOLECREATE_NEW_PROCESS_GROUP。(仅限Windows)

1.3。例外

在新程序开始执行之前,子进程中引发的异常将在父进程中重新提出。另外,异常对象将会有一个额外的属性被调用child_traceback,这是一个字符串,其中包含来自孩子视角的回溯信息。

最常见的例外是OSError。例如,尝试执行不存在的文件时会发生这种情况。应用程序应该准备OSError例外。

ValueError如果Popen使用无效参数调用A 将会被提出。

check_call()如果被调用的进程返回一个非零的返回码,check_output()将会引发CalledProcessError

1.4。安全

与其他一些popen函数不同,此实现不会隐式调用系统shell。这意味着所有字符(包括shell元字符)都可以安全地传递给子进程。显然,如果shell被显式调用,那么应用程序有责任确保所有空白和元字符都被适当引用。

2. Popen对象

Popen类的实例有以下方法:

Popen.poll()

检查子进程是否已终止。设置并返回returncode属性。

Popen.wait()

等待子进程终止。设置并返回returncode属性。

警告

这会在使用stdout=PIPE和/或stderr=PIPE和子进程产生足够的输出到管道时发生死锁,从而阻塞等待OS管道缓冲区接受更多数据。使用communicate()以避免这种情况。

Popen.communicate(input=None)

与流程进行交互:将数据发送到stdin。从stdout和stderr中读取数据,直到达到文件结尾。等待进程终止。可选的输入参数应该是要发送到子进程的字符串,或者None如果没有数据应该发送给子进程。

communicate() returns a tuple (stdoutdata, stderrdata).

请注意,如果要将数据发送到进程的stdin,则需要使用创建Popen对象stdin=PIPE。同样,要获得除None结果元组以外的任何内容,您需要提供stdout=PIPE和/或stderr=PIPE也可以。

注意

读取的数据缓冲在内存中,所以如果数据量很大或无限,就不要使用这种方法。

Popen.send_signal(signal)

将信号发送给子类。

注意

在Windows上,SIGTERM是别名terminate()。可以将CTRL_C_EVENT和CTRL_BREAK_EVENT发送到以包含的creationflags参数开始的进程CREATE_NEW_PROCESS_GROUP

2.6版本中的新功能。

Popen.terminate()

停止子类。在Posix操作系统上,该方法向孩子发送SIGTERM。在Windows上调用Win32 API函数TerminateProcess()来停止该子项。

2.6版本中的新功能。

Popen.kill()

停止子类。在Posix操作系统上,该函数向孩子发送SIGKILL。在Windows上kill()是别名terminate()

2.6版本中的新功能。

以下属性也可用:

警告

使用communicate()而不是.stdin.write.stdout.read.stderr.read避免死锁由于任何其他操作系统管缓冲区填满并阻塞子进程。

Popen.stdin

如果stdin参数是PIPE,则该属性是为子进程提供输入的文件对象。否则,它是None

Popen.stdout

如果stdout参数是PIPE,则此属性是提供子进程输出的文件对象。否则,它是None

Popen.stderr

如果stderr参数是PIPE,则此属性是一个文件对象,它提供子进程的错误输出。否则,它是None

Popen.pid

子进程的进程ID。

请注意,如果将shell参数设置为True,则这是生成的shell的进程ID。

Popen.returncode

子类返回代码,由poll()wait()(和间接地communicate())设置。一个None值表示进程尚未结束。

负值-N表示该孩子被信号终止N(仅限Unix)。

3. Windows Popen助手

STARTUPINFO级和以下常量仅适用于Windows。

class subprocess.STARTUPINFO

部分支持Windows STARTUPINFO(https://msdn.microsoft.com/en-us/library/ms686331(v = vs.85%29.aspx)结构用于Popen创建。

dwFlags

一个位域,用于确定STARTUPINFO进程创建窗口时是否使用某些属性。

代码语言:javascript
复制
si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW

hStdInput

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是该进程的标准输入句柄。如果STARTF_USESTDHANDLES未指定,则标准输入的默认值是键盘缓冲区。

hStdOutput

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是该进程的标准输出句柄。否则,该属性将被忽略,标准输出的默认值是控制台窗口的缓冲区。

hStdError

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是该进程的标准错误句柄。否则,该属性将被忽略,标准错误的默认值是控制台窗口的缓冲区。

wShowWindow

如果dwFlags指定STARTF_USESHOWWINDOW,则此属性可以是可以nCmdShow在ShowWindow 的参数中指定的任何值(https://msdn.microsoft.com/zh-cn/library/ms633548(v = vs.85%29.aspx)函数,除了SW_SHOWDEFAULT。否则,该属性将被忽略。

SW_HIDE为此属性提供。它在Popen被调用时使用shell=True

3.1。常量

subprocess模块暴露下列常量。

subprocess.STD_INPUT_HANDLE

标准输入设备。最初,这是控制台输入缓冲区,CONIN$

subprocess.STD_OUTPUT_HANDLE

标准输出设备。最初,这是活动控制台屏幕缓冲区,CONOUT$

subprocess.STD_ERROR_HANDLE

标准的错误设备。最初,这是活动控制台屏幕缓冲区,CONOUT$

subprocess.SW_HIDE

隐藏窗口。另一个窗口将被激活。

subprocess.STARTF_USESTDHANDLES

指定STARTUPINFO.hStdInputSTARTUPINFO.hStdOutputSTARTUPINFO.hStdError属性包含的附加信息。

subprocess.STARTF_USESHOWWINDOW

指定该STARTUPINFO.wShowWindow属性包含附加信息。

subprocess.CREATE_NEW_CONSOLE

新进程有一个新的控制台,而不是继承其父控制台(默认)。

该标志始终在Popen创建时设置shell=True

subprocess.CREATE_NEW_PROCESS_GROUP

一个Popen creationflags参数指定一个新的进程组将被创建。该标志对于os.kill()在子进程上使用是必需的。

如果CREATE_NEW_CONSOLE被指定,该标志被忽略。

4.用子流程模块替换旧功能

在本节中,“a变成b”表示b可以用作a的替换。

注意

如果执行的程序无法找到,本节中的所有“a”功能都将无效(或多或少); OSError代替“b” 代替。

另外,如果请求的操作产生非零返回码,则替换使用check_output()将失败CalledProcessError。输出仍然可用作output引发异常的属性。

在以下示例中,我们假设相关功能已从subprocess模块导入。

4.1。替换/ bin / sh外壳反引号

代码语言:javascript
复制
output=`mycmd myarg`

变为:

代码语言:javascript
复制
output = check_output(["mycmd", "myarg"])

4.2。更换壳管道

代码语言:javascript
复制
output=`dmesg | grep hda`

变为:

代码语言:javascript
复制
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

启动p2后,p1.stdout.close()调用非常重要,以便p1在p1之前退出时接收SIGPIPE。

或者,对于可信输入,shell自己的管线支持仍可以直接使用:

代码语言:javascript
复制
output=`dmesg | grep hda`

变为:

代码语言:javascript
复制
output=check_output("dmesg | grep hda", shell=True)

4.3。更换os.system()

代码语言:javascript
复制
status = os.system("mycmd" + " myarg")
# becomes
status = subprocess.call("mycmd" + " myarg", shell=True)

笔记:

  • 通过shell调用程序通常是不需要的。一个更现实的例子如下:try:retcode = call(“mycmd”+“myarg”,shell = True)如果retcode <0:print >> sys.stderr, “孩子被信号终止”,-retcode else:print >> sys.stderr,“孩子返回”,除OSError之外的编码为e:print >> sys.stderr,“执行失败:”,e4.4。替换os.spawnfamilyP_NOWAIT例如:PID = os.spawnlp(os.P_NOWAIT, “/斌/ mycmd”, “mycmd”, “myarg”)==> PID = POPEN([ “/ bin中/ mycmd”, “myarg”])pidP_WAIT例如:retcode = os.spawnlp(os.P_WAIT,“/ bin / mycmd”,“mycmd”,“myarg”)==> retcode = call([“/ bin / mycmd”,“myarg”])例子: os.spawnlp(os.P_NOWAIT,path,args)==> Popen([path] + args [1:])环境示例:os.spawnlpe(os.P_NOWAIT,“/ bin / mycmd”,“mycmd”,“ myarg“,env)==> Popen([”/ bin / mycmd“,”myarg“],env = {”PATH“:”/usr/bin"})4.5。更换os.popen()os.popen2()os.popen3()rc = pipe.close()如果rc不是None且rc >> 8:print“有一些错误”==> process = Popen(“cmd”,shell = True,stdin = PIPE)... process .stdin.close()if process.wait()!= 0:print“有一些错误”4.6。从中取代功能popen2模块(child_stdout,child_stdin)= popen2.popen2( “somestring”,BUFSIZE,模式)==> P = POPEN( “somestring”,壳=真,BUFSIZE = BUFSIZE,标准输入= PIPE,由于输出= PIPE,close_fds =真) (child_stdout,child_stdin)=(p.stdout,p.stdin)在Unix上,popen2也接受一个序列作为执行命令,在这种情况下,参数将直接传递给程序,而不需要shell干预。这个用法可以替换为:(child_stdout,child_stdin)= popen2.popen2([“mycmd”,“myarg”],bufsize,mode)==> p = Popen([“mycmd”,“myarg”],bufsize = BUFSIZE,标准输入= PIPE,由于输出= PIPE,close_fds =真)(child_stdout,child_stdin)=(p.stdout,p.stdin)popen2.Popen3popen2.Popen4基本上如工作subprocess.Popen,不同之处在于:
  • Popen 如果执行失败会引发异常。
  • capturestderr参数被替换为标准错误的说法。
  • stdin=PIPE并且stdout=PIPE必须指定。
  • 默认情况下,popen2关闭所有文件描述符,但必须close_fds=True使用Popen

5.注意

5.1。在Windows上将参数序列转换为字符串

在Windows上,参数序列被转换为可以使用以下规则解析的字符串(它对应于MS C运行时使用的规则):

  • 参数是由空白分隔的,它是一个空格或一个制表符。
  1. 无论内部包含空格,用双引号括起来的字符串都被解释为单个参数。引用的字符串可以嵌入参数中。
  • 前面加一个反斜杠的双引号被解释为文字双引号。
  • 反斜杠从字面上解释,除非它们立即在双引号之前。
  • 如果反斜杠立即在双引号之前,则每对反斜杠都将被解释为文字反斜杠。如果反斜杠的数量是奇数,则最后一个反斜杠将转义下一个双引号,如规则3所述。

扫码关注腾讯云开发者

领取腾讯云代金券