Python 之 子进程模块 subprocess

  运行python的时候,我们都是在创建并运行一个进程,linux中一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在python中,我们通过标准库中的subprocess包来fork一个子进程,并且运行一个外部的程序。subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所欲我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

二、使用

1. call

  执行命令,返回状态码,shell = True允许shell命令时字符串形式

subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True)

2. check_call

  执行命令,如果执行状态码是0,则返回0,否则抛出异常

subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True) 

3. check_output

  执行命令,如果状态码是0,则返回执行结果,否则抛出异常

subprocess.check_output(["echo", "Hello World!"])
subprocess.check_output("exit 1", shell=True)

4. subprocess.Popen(...) 

  用于执行复杂的系统命令

参数:

  args: 可以是字符串或者序列类型(如:list, tuple)。默认的,要执行的程序应该是序列的第一个字段,如果是单个字符串,它的解析依赖于平台。在unix中,如果args是一个字符串,那么这个字符串解释成被执行程序的名字或路径,然而,这种情况只能用在不需要参数的程序。
  bufsieze: 指定缓冲。0表示无缓冲,1表示缓冲,任何其他的整数值表示缓冲大小,负数值表示使用系统默认缓冲,通常表示完全缓冲。默认值为0即没有缓冲。
  stdin, stdout, stderr:分别表示程序的标准输入,输出,错误句柄
  preexec_fn : 只在unix平台有效,用于指定一个可执行对象,它将在子进程中运行之前被调用
  close_fds : 在windows平台下,如果close_fds被设置为true,则新创建的子进程将不会继承父进程的输入,输出,错误管道。所以不能将close_fds设置为true同时重定向子进程的标准输入,输出与错误。
  shell : 默认值为False, 声明了是否使用shell来执行程序,如果shell=True,它将args看做一个字符串,而不是一个序列。在unix系统中,且shell=True, shell默认使用/bin/sh。
  cwd : 用于设置子进程的当前目录。当它不为None时,子程序在执行前,它的当前路径会被替换成cwd的值。这个路径并不会被添加到可执行程序的搜索路径,所以cwd不能是相对路径。
  env : 用于指定子进程的环境变量。如果env=None,子进程的环境变量将从父进程中继承。当它不为None时,它是新进程的环境变量的映射。可以用它来代替当前进程的环境。
  universal_newlines : 不同系统的换行符不同, 文件对象stdout和stderr都被以文本文件的方式打开
  startupinfo 与 createionflags只在windows下生效。将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等

执行普通命令:

import subprocess
ret1 = subprocess.Popen(["mkdir","t1"])
ret2 = subprocess.Popen("mkdir t2", shell=True)

终端输入的命令分为两种:

  输入即可得到输出,如:ifconfig
  输入进行某环境,依赖在输入,如: python

import subprocess
obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
obj.stdin.close()

cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()

print(cmd_out)
print(cmd_error)

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

out_error_list = obj.communicate()
print(out_error_list)

import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate('print("hello")')
print(out_error_list)

5、subprocess.run()方法在Python3.5增加的

  subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False)
  run()默认不会捕捉到标准输出和标准错误输出,要捕捉的话,可以为标准输出和标准错误输出指定subprocess.PIPE(一个特殊值,可被用于Popen的stdin, stdout或 stderr参数,表示一个标准流的管道应该被打开, Popen.communicate()用的最多)。

  args :args应该是一个字符串或者一个序列。
  timeout:设置超时时间,会传递给subprocess.Popen.communicate()。如果超时,子进程会被杀死并等待。子进程被终止后会报告一个 TimeoutExpired异常。
  input参数会传递给subprocess.Popen.communicate(),从而作为subprocess的标准输入。当我们使用的时候,内部的Popen对象会自动创建stdin=PIPE,stdin参数可能不会被使用。
  check:如果check参数为True,且进程退出的时候得到退出码一个非0的值,会报告一个 CalledProcessError异常
  shell:shell参数默认为False,此时arg参数应该是一个列表。subprocess.run(["ls","-l"]) ; 当shell=True时,args可以是一个字符串。subprocess.run("ls -l",shell=True)。

>>> ret = subprocess.run(["ls", "-l"]) # doesn't capture output 
CompletedProcess(args=['ls', '-l'], returncode=0)
>>> print(ret.stdout)
None

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

>>> ret1 = 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')

>>> print(ret.stdout)
b'crw-rw-rw- 1 root root 1, 3 6\xe6\x9c\x88 8 06:50 /dev/null\n'
call方法

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
call()方法等价于:run(..., check=True)和run()方法类所以,只是不支持input参数和check参数;

注意: 不要在这个方法里使用stdout=PIPE 或 stderr=PIPE,当到一个管道的输出填满系统的管道缓存时,子进程会被阻塞。


check_call方法

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
check_call()方法等价于: run(..., check=True, stdout=PIPE).stdout

3.1新增,3.3时增加了timeout参数,3.4时增加了对关键字参数的支持

check_output()方法

内部调用的是run()方法,但是会捕捉到stdout

>>> ret = subprocess.check_output(["ls", "-l", "/dev/null"])
>>> print(ret)
b'crw-rw-rw- 1 root root 1, 3 6\xe6\x9c\x88 8 06:50 /dev/null\n'
Popen类

上面的四个方法本质上调用的都是subprocess中的Popen类。

Popen对象都有以下方法:

poll() : 检查子进程是否已经终止,返回一个returncode,相当于exit code。

wait() : 等待子进程终止,返回一个returncode

communicate(input=None) :和进程进行交互:发送数据到stdin;从stdout和stderr读取数据,直到读取完。等待进程终止。可选参数input会传递数据给子进程,当input=None事,没有数据传递给子进程。 communicate() 返回一个元组 (stdout, stderr). 注意: 读取的数据在内存的buffer中,所以当数据大小大于buffer或者没有限制时,不要使用这个方法。
subprocess方法简单总结

参考博客:

  http://blog.csdn.net/pipisorry/article/details/46972171 #subprocess所有办法

  http://blog.csdn.net/b_h_l/article/details/10080171 #图片

  http://www.cnblogs.com/sunailong/p/5162748.html #注释讲解

  http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html #基础举例

posted @ 2017-08-12 09:42  细雨蓝枫  阅读(595)  评论(0编辑  收藏  举报