python子进程模块subprocess详解与应用实例 之一
subprocess--子进程管理器
一、subprocess 模块简介
subprocess最早是在2.4版本中引入的。
subprocess模块用来生成子进程,并可以通过管道连接它们的输入/输出/错误,以及获得它们的返回值。
它用来代替多个旧模块和函数:
os.system
os.spawn*
os.popen*
popen2.*
commands.*
关于这个模块可以取代的旧函数可以参见 subprocess-replacements 一节。
POSIX用户(Linux, BSD, etc)还可以安装和使用更新的subprocess32模块来代替python 2.7版本中的subprocess.
subprocess32虽然是一个低版本,但在有些情况下效果更好。
1.1. 使用 subprocess模块
启动子进程的推荐方式是使用下面的便利功能。
当这些还不能满足需求时,就需要使用底层的Popen接口。
1. subprocess.call
语法:
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
语义:
运行由args指定的命令,直到命令结束后,返回 返回码的属性值。
上面的参数是最常见的方式,下面是示例代码:
>>>
>>> subprocess.call(["ls", "-l"])
0
>>> subprocess.call("exit 1", shell=True)
1
WARNING: 使用 shell=True 是一种安全保护机制。
NOTE: 在使用这个函数时,不要使用 stdout=PIPE 或 stderr=PIPE 参数,
不然会导致子进程输出的死锁。
如果要使用管道,可以在 communicate()方法中使用Popen
示例代码:
import subprocess
rc = subprocess.call(["ls","-l"])
可以通过一个shell来解释一整个字符串:
import subprocess
out = subprocess.call("ls -l", shell=True)
out = subprocess.call("cd ..", shell=True)
使用了shell=True这个参数。
这个时候,我们使用一整个字符串,而不是一个表来运行子进程。
Python将先运行一个shell,再用这个shell来解释这整个字符串。
shell命令中有一些是shell的内建命令,这些命令必须通过shell运行,$cd。
shell=True允许我们运行这样一些命令。
2. subprocess.check_call
语法:
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
语义:
运行由args指定的命令,直到命令执行完成。
如果返回码为零,则返回。否则,抛出 CalledProcessError异常。
CalledProcessError对象包含有返回码的属性值。
上面显示的参数仅仅是最常见的,下面是用户更常用的参数。
示例代码如下:
>>>
>>> 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
这个函数在python 2.5版本中引入。
WARNING: 使用 shell=True 是一种安全机制。
NOTE: 不要在这个函数中使用 stdout=PIPE 或 stderr=PIPE, 否则会造成子进程死锁。
如果需要使用管道,可以在 communicate()方法中使用Popen.
3. subprocess.check_output
语法:
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
语义:
运行args定义的命令,并返回一个字符串表示的输出值。
如果返回码为非零,则抛出 CalledProcessError异常。
示例代码:
>>>
>>> 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参数:
>>>
>>> subprocess.check_output(
... "ls non_existent_file; exit 0",
... stderr=subprocess.STDOUT,
... shell=True)
'ls: non_existent_file: No such file or directory\n'
这个函数在python 2.7版本中引入。
WARNING: 使用 shell=True 是一种安全机制。
NOTE: 不要在这个函数中使用 stdout=PIPE 或 stderr=PIPE, 否则会造成子进程死锁。
如果需要使用管道,可以在 communicate()方法中使用Popen.
4. subprocess.PIPE
使用Popen时,用于 stdin, stdout和stderr参数的特殊值,表示打开连接标准流的管道。
5. subprocess.STDOUT
使用Popen时,用于 stderr 参数的特殊值,表示将标准错误重定向到标准输出的同一个句柄。
6. 异常 subprocess.CalledProcessError
当由 check_call()或 check_output()运行的进程返回非零状态值时抛出的异常。
7. returncode
子进程的退出状态。
8. cmd
子进程执行的命令。
9. output
如果check_output()抛出异常时,子进程的输出值。
否则,没有这个值。
1.1.1. 常用的参数
为了支持各种用户使用情况 ,Popen构建函数接收多种可选参数。
对于最典型的情况,许多参数都保留有安全的默认值,这些最常用的方式如下:
1. args
所有的函数都需要这个参数,并且它是一个字符串,或者是程序的参数序列。
提供一个参数序列是更推荐的方式,因为这样能允许模块接收空格 或 引号中的参数。
如果传递的是单个字符串,要么 shell=True, 或都要么 字符串就程序名字,并且不能带参数。
2. stdin, stdout 和 stderr
stdin, stdout和stderr指定了执行程序的标准输入,标准输出和标准错误的文件句柄。
它们的值可以是PIPE, 一个存在的文件描述符(正整数),一个存在的文件对象,或 None.
PIPE 表示创建一个连接子进程的新管道。
默认值 为 None, 表示不做重定向。
子进程的文件句柄可以从父进程中继承得到。
另外,stderr可以设置值为 STDOUT,表示子进程的错误数据可以和标准输出是同一个文件句柄。
当stdout 或 stderr的值为管道 并且 universal_newlines的值为真时,
对于以 ‘U'模式参数打开的新行,所有行的结束都会转换成'\n'。
3. shell
如果 shell的值为 True, 则指定的命令行会通过shell来执行。
如果你使用Python来作为流程控制,那这样的设置会很有用,因为它提供了绝大多数的系统shell命令且可以很方便地使用
shell的各种功能,如 shell 管道,文件名通配符,环境变量扩展,以及用户目录扩展符 ~。
但是,需要注意的是,Python 提供了类似shell功能的实现。
WARNING: 执行不受信任来源的shell命令会是一个严重的安全问题。
基于这一点,shell=True 是不建议的。
示例代码如下:
>>>
>>> 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=True时,pipes.quote()可以被用于转译空格,shell的字符等。
1.1.2. Popen构建函数
subprocess中更底层的进程创建和管理可以通过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()函数来执行子程序。
参数解析:
args: 一个程序参数序列,或者单个字符串。
默认的,要执行的程序应该是序列的第一个字段。
如果单个字符串,它的解析依赖于平台
在Unix中,如果 args是一个字符串,那么这个字符串解释成被执行程序的名字或路径。
然而,这种情况只能用在不需要参数的程序。
NOTE: 当对args确定了正确的分隔符后,shlex.split()就很有用,特别是在复杂的情况下:
>>>
>>> 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!
NOTE: 选项(如 -input) 和 参数(如 eggs.txt) 在shell中是用空格分隔成分离的列表元素。
如果参数需要引号或反斜线,则它们会是一个单一列表元素。
shell参数(默认值为False)声明了是否使用shell来执行程序。
如果 shell=True, 它将args看作是一个字符串,而不是一个序列。
在Unix系统,且 shell=True时,shell默认使用 /bin/sh.
如果 args是一个字符串,则它声明了通过shell执行的命令。这意味着,字符串必须要使用正确的格式。
如果 args是一个序列,则第一个元素就是命令字符串,而其它的元素都作为参数使用。
可以这样说,Popen等价于:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
bufsize: 如果指定了值,则它和内建函数 open()对应的参数有相同的意义:
0 -- 表示不缓冲
1 -- 表示缓冲
任何其它的正数值表示buffer的大小。
负数值表示使用系统默认值,通常表示完全缓冲。
它的默认值为零。
NOTE: 如果遇到性能问题,建议将bufsize设置成 -1 或足够大的正数(如 4096)。
executable: 指定了用于代替执行的程序。它极少会用到。
stdin, stdout, stderr:指定了执行程序的标准输入,标准输出和标准错误的文件句柄。
有效的值可以是 PIPE, 一个存在的文件描述符,或存在的文件对象,或 None.
默认值为 None。
stderr可以设置成STDOUT, 它表示将子进程的stderr数据重定向到stdout.
preexec_fn: 如果它被设置成可调用对象,那么这个对象会在子进程执行前被子进程调用,只用于Unix.
close_fds: 如果设置为True, 则在子进程被执行前,除0,1和2之外的所有文件描述符都将被关闭,只用于Unix。
cwd: 当它不为 None时,子程序在执行前,它的当前路径会被替换成 cwd的值。
这个路径并不会被添加到可执行程序的搜索路径,所以cwd不能是相对路径。
env: 当它不为 None时,它是新进程的环境变量的映射。
可以用它来代替当前进程的环境。
universal_newlines: 为真时,文件对象 stdout和 stderr都被以文本文件的方式打开
示例代码:
1. Popen对象创建后,主程序不会自动等待子进程完成。
我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block):
import subprocess
child = subprocess.Popen(["ping","-c","5","www.google.com"])
print("parent process")
从运行结果中看到,父进程在开启子进程之后并没有等待child的完成,而是直接运行print。
2. 对比等待的情况:
import subprocess
child = subprocess.Popen(["ping","-c","5","www.google.com"])
child.wait()
print("parent process")
此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:
child.poll() # 检查子进程状态
child.kill() # 终止子进程
child.send_signal() # 向子进程发送信号
child.terminate() # 终止子进程
子进程的PID存储在child.pid
3. 可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,
并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):
import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print(out)
subprocess.PIPE实际上为文本流提供一个缓存区。
child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。
child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。
要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。
4. 还可以利用communicate()方法来使用PIPE给子进程输入:
import subprocess
child = subprocess.Popen(["cat"], stdin=subprocess.PIPE)
child.communicate("vamei")
我们启动子进程之后,cat会等待输入,直到我们用communicate()输入"vamei"。
通过使用subprocess包,我们可以运行外部程序。这极大的拓展了Python的功能。
如果你已经了解了操作系统的某些应用,你可以从Python中直接调用该应用(而不是完全依赖Python),
并将应用的结果输出给Python,并让Python继续处理。
shell的功能(比如利用文本流连接各个应用),就可以在Python中实现。
1.1.3.异常
在开始执行新程序之前,子进程抛出的异常,会被重新抛出到父进程。
另外,异常对象会有一个额外的属性,叫做 child_traceback, 它是一个字符串,包含从子程序的观察点追踪到的信息。
最常见的抛出的异常是 OSError, 当它发生时,通常是我们执行了一个不存在的文件。应用程序应当要能处理这个异常。
如果使用无效的参数调用 Popen,会抛出 ValueError异常。
如果被调用进程的返回码不为零,则check_call()和check_output()会抛出 CalledProcessError异常。
1.1.4. 安全
Unlike some other popen functions, this implementation will never call a system shell implicitly.
This means that all characters, including shell metacharacters, can safely be passed to child processes.
Obviously, if the shell is invoked explicitly, then it is the application’s responsibility to ensure that
all whitespace and metacharacters are quoted appropriately.
from:http://blog.chinaunix.net/uid-26000296-id-4461522.html
python子进程模块subprocess详解与应用实例 之一的更多相关文章
- python子进程模块subprocess详解与应用实例 之三
二.应用实例解析 2.1 subprocess模块的使用 1. subprocess.call >>> subprocess.call(["ls", " ...
- python子进程模块subprocess详解与应用实例 之二
1.2. Popen 对象 Popen类的实例有下列方法: 1. Popen.poll() 检查子进程是否已经结束,设置并返回返回码值. 2. Popen.wait() 等待子进程结束,设置并返回返回 ...
- python子进程模块subprocess详解
subprocess--子进程管理器一.subprocess 模块简介subprocess最早是在2.4版本中引入的.subprocess模块用来生成子进程,并可以通过管道连接它们的输入/输出/错误, ...
- python之模块datetime详解
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之模块datetime详解 import datetime #data=datetime.dat ...
- Python Deque 模块使用详解,python中yield的用法详解
Deque模块是Python标准库collections中的一项. 它提供了两端都可以操作的序列, 这意味着, 你可以在序列前后都执行添加或删除. https://blog.csdn.net/qq_3 ...
- python——pickle模块的详解
pickle模块详解 该pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议. “Pickling”是将Python对象层次结构转换为字节流的过程, “unpickling”是反 ...
- Python编程之子进程管理(subprocess)详解
引言 在写程序时,我们无法避免需要运行外部程序,相较于功能比较简单的os.system(),更加倾向于使用subprocess模块来执行外部程序. 模块介绍 subprocess.run() 使用su ...
- python datetime模块参数详解
Python提供了多个内置模块用于操作日期时间,像calendar,time,datetime.time模块,它提供 的接口与C标准库time.h基本一致.相比于time模块,datetime模块的接 ...
- python re模块findall()详解
今天写代码,在写到郑泽的时候遇到了一个坑,这个坑是re模块下的findall()函数. 下面我将结合代码,记录一下 import re string="abcdefg acbdgef abc ...
随机推荐
- canvas 绘制文本
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- Friendly ARM linux交叉编译问题解决
ARM-LINUX-GCC 安装参考:(笔记)Ubuntu下安装arm-linux-gcc-4.4.3.tar.gz (交叉编译环境) 然而安装完成之后运行 arm-linux-gcc -v (注意g ...
- easyui1.4 汉化出问题
easyui 1.4 的textbox 验证汉化不了,需要在easyui-lang-zh_CN.js 加入 if ($.fn.textbox){ $.fn.textbox.defaults.missi ...
- C++之指针使用
C++指针使用的好坏直接反映了编程人员水平的高低,下面从指针和数组的区别.指针参数是如何传递内存.野指针.malloc/free.new/delete和内存耗尽怎么办方面进行总结. 一 指针和数组对比 ...
- ActionContext介绍(在Struts2中)
一种属性的有序序列,它们为驻留在环境内的对象定义环境.在对象的激活过程中创建上下文,对象被配置为要求某些自动服务,如同步.事务.实时激活.安全性等等.多个对象可以存留在一个上下文内.也有根据上下文理解 ...
- Java集合总结之Collection整体框架
前段时间一直在忙一个物联网的项目,所以Java的学习一直搁置,从今天开始继续学习!望大家多提宝贵意见! java.util包中包含了一些在Java 2中新增加的最令人兴奋的增强功能:类集.一个类集(c ...
- 【java规则引擎】一个基于drools规则引擎实现的数学计算例子
最近在研究JBPM工作流引擎,发现JBPM是基于Drools的,官方文档查看得知Drools是一款规则引擎.兴趣之下,仔细了解了下 Drools,Drools作为JBoss出品的一款开源推理和规则引擎 ...
- 十九、python沉淀之路--装饰器
一.实现装饰器的预备知识 装饰器 = 高阶函数 + 函数嵌套 + 闭包 1.高价函数定义: 1.函数接收的参数是一个函数名 2.函数的返回值是一个函数名 3.满足上述条件任意一个,都可称之 ...
- add-apt-repository 添加
add-apt-repository 添加 需要安装的软件包 apt-get install python-software-properties 除此之外还要安装 software-propert ...
- POI 单元格
OI 单元格合并中的CellRangeAddress 参数: CellRangeAddress(int, int, int, int) 参数:起始行号,终止行号, 起始列号,终止列号 sheet.ad ...