subprocess模块允许你创建新进程,链接到他们的输入/输出/错误 管道上,去获取他们的返回码。这个模块主要是为了替换一些旧的模块和函数,比如os.systemos.spawn*

使用subprocess模块

run函数

推荐的调用子进程的方式是使用run()函数,它可以处理所有的情况,在一些更高级的用例中,可以直接使用底层的Popen接口。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False)

args是你要运行的命令,然后等待命令运行结束,然后返回一个CompletedProcess实例

上面显示的参数是最常使用的,在下面的Frequently Used Arguments有详细介绍。它默认不会捕获stdout或者stderr,为了捕获这些信息,给stdout或者stderr参数传递PIPE

timeout参数会被传递给Popen.communicate(),如果到了timeout,子进程会被kill掉,在子进程被杀死之后会重新引发TimeoutExpired异常

输入参数会被传递给Popen.communicate(),然后会被作为子进程的输入。如果要使用这个参数,传递的必须是一个二进制序列,或者当universal_newlines=True的时候可以传递一个字符串。当使用这个参数的时候,内部的Popen对象会自动的加入stdin=PIPE创建对象,同时stdin参数将不会被使用。

如果check参数为True,如果子进程以非0状态码退出的话,一个CalledProcessError异常将会被引发。异常会保持参数,退出码,stdout以及stderr,如果能捕获的话。

例子:

1
2
3
4
5
6
7
8
9
10
11
>>> subprocess.run(["ls", "-l"]) # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

基本上最简单的用法就是check=True,然后stdout=PIPE直接调用run函数就好了

CompletedProcess

从run函数的返回值,表示一个进程已经结束

  • args: 用来启动进程的参数,会是一个列表或者字符串
  • returncode: 子进程的退出码,如果是0表示运行成功,负数-N表示子进程被信号N终止了
  • stdout: 从子进程中捕获stdout,二进制序列,如果run函数加上universal_newlines=True调用就是一个字符串,如果什么都没捕获的话就是一个None
  • stderr: 跟上面一样
  • check_returncode(): 如果returncode不是0,则引发一个CalledProcessError

DEVNULL

可以在stdin, stdout或者stderr中作为Popen的参数,用来指示os.devnull文件将会被使用

PIPE

可以在stdin, stdout或者stderr中作为Popen的参数,用来指示标准流的管道应该被打开。

STDOUT

用在Popen的stderr参数,用来指示标准错误应该和标准输出一同处理

CalledProcessError

  • returncode: 子进程的退出码,如果是0表示运行成功,负数-N表示子进程被信号N终止了
  • cmd: 用来启动进程的命令
  • output: 如果被run或者check_output捕获就是子进程的输出,否则是None
  • stdout:
  • stderr

Frequently Used Arguments

为了支持更广泛的使用,Popen构造器和一些有用的函数,接受大量的可选参数。对于大部分典型使用来说,这些参数中的大部分都可以使用其默认值。经常需要使用的参数是这些:

  • args 每一次调用都需要这个参数,应该是一个字符串或者是程序的参数序列。通常建议传递参数序列,因为这样可以允许模块更好的处理转义和参数引用,比如在文件名中允许空格。如果传递了单个的字符串,shell参数应该为True或者是程序调用的时候不需要额外参数
  • stdin, stdout, stderr 分别指定了程序的标准输入,标准输出和标准错误的文件处理器。有效的值是PIPEDEVNULL,一个存在的文件描述符,一个存在的文件对象和None。PIPE指定了一个连接到子进程的管道应该被创建。DEVNULL指定了这个特殊的文件os.devnull会被使用。默认值None说明没有重定向发生。子进程的文件处理器会继承父进程的。另外,stderr将会是STDOUT,表明子进程的stderr数据会和stdout一块捕获。
  • universal_newlines 如果为False,stdin, stdout, stderr将会以二进制流的方式打开,并且没有行结束符。如果为True,将会以文本模式打开,并且使用locale.getpreferredencoding(False)返回的编码方式。对于stdin,\n将会被转换成默认的行分隔符os.linesep。对于stderr和stdout,所有的行结束都会被转换成\n
  • shell 如果为True,指定的命令将会通过shell来执行,在你主要用Python来做控制,但是又想有shell的便利性的时候很有用,比如shell管道,文件名通配符,环境变量扩展,~用户家目录的扩展。然而,Python自己也实现了很多shell特性的东西,比如glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser()shutil