目录

  • 目录
  • 前言
  • 软件环境
  • 认识subprocess
  • Popen Constructor构造函数
    • Class Popen的参数

      • args

        • 调用程序
        • 调用Shell指令
      • stdinstdoutstderr
        • 实时获取子程序输出
        • 一次获取子程序的全部输出
        • 将标准错误和标准输出一起输出
      • shell
      • bufsize
      • close_fds
      • 其他参数含义
    • Popen成员函数
      • Popenpoll
      • PopenwaittimeoutNone
      • PopencommunicateinputNonetimeoutNone
      • Popensend_signalsignal
      • Popenterminate
      • Popenkill
    • Popen成员属性
      • Popenpid
      • Popenreturncode
      • Popenstdin
        • 输入交互
      • Popenstdout
        • 连续的输入输出交互
      • Popenstderr
  • subprocess函数
    • subprocesscall
    • subprocesscheck_call
    • subprocesscheck_output
  • 最后

前言

subpocess用于在父进程中创建子进程,如果你希望在Python程序中调用外部程序,如:Powershell、shell、cmd、bat。subprocess将会是一个非常好的选择。

软件环境

  • 系统

    • Win 10
  • 软件
    • Python 3.4.4
    • IPython 4.0.0

认识subprocess

还是那句话,最高效的方法不过看官方文档,传送门:这里
subprocess:The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:

os.system
os.spawn*
os.popen*
popen2.*
commands.*

subprocess的诞生是为了替代、整合以前几种旧的创建子进程的方法,能够实现以管道的形式连接子进程的stdinstdoutstderr,并且子进程会返回一个returncode给父进程。与C语言中的fock实现类似的功能。
Execute a child program in a new process. On POSIX, the class uses os.execvp() like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function
在POSIX类型系统中会使用os.execvp()来执行子程序,而在windows环境中会使用CreateProcess()函数来执行,这篇博文主要记录在windows环境下的使用。

Popen Constructor(构造函数)

subprocess拥有数个通过不同的方式来创建子进程的函数,但是subprocess只有一个Popen类,同样是用于创建子进程。使用Class Popen创建的对象拥有Popen的成员属性和方法。

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

在Python 3.2之后的版本Popen对象添加了下面这种写法:
on exit, standard file descriptors are closed, and the process is waited for.

with Popen(["ifconfig"], stdout=PIPE) as proc:log.write(proc.stdout.read())

下面介绍Popen类的参数含义。

Class Popen的参数

args

args :should be a sequence of program arguments or else a single string.
args参数可以是String类型或者sequence类型,作为子程序的声明。在Windows中调用的子进程API是CreateProcess([String]),所以可以接受诸如notepad.exe test.txt这样的字符串来执行。但是在Linux的环境下需要接受List类型对象来分隔程序名和参数。如果是序列类型,序列的第一个参数一般也作为子程序的路径,之后的元素作为传入子程序的参数。官方建议args参数使用List类型对象

调用程序

调用一个Powershell脚本程序:

args = [r"C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe","-ExecutionPolicy","Unrestricted",r"E:\Users\oe-fanguiju\Desktop\SendMail.ps1",str(bodyStr)]
ps = subprocess.Popen(args,stdout=subprocess.PIPE)

注意:在String前加入r是为了避免出现SyntaxError: (unicode error)

调用Shell指令

序列化传入参数 shlex.split()
我们还可以使用shlex.split()函数来将我们所需要执行的指令序列化后再赋值给args参数。

>>> import shlex, subprocess
>>> command_line = 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!

stdin\stdout\stderr

stdin\stdout\stderr指定了子程序的标准输入、输出、错误的文件句柄(file handles)。他们可以是PIPE管道、DEVNULL(DEVNULL indicates that the special file os.devnull will be used.)、文件描述符(existing file descriptor 一个正整数)或已存在的文件对象(file object)。当他的值是None时,不会发生重定向,子进程的文件句柄将会继承父进程。而且stderr=subprocess.STDOUT能够将标准错误的文件句柄设成标准输出(子程序的标准错误汇合到标准输出)。将stdout/stderr指定为subprocess.PIPE,这样在Popen被调用的时候会在父进程和子进程之间建立管道,子进程的标准输出和错误输出都重定向到管道,可以被父进程获取。

实时获取子程序输出

p = subprocess.Popen("/etc/service/tops-cmos/module/hadoop/test.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
returncode = p.poll()
while returncode is None:   #检查子程序是否结束line = p.stdout.readline()    #若没有,则获取子程序的输出returncode = p.poll()line = line.strip()print line
print returncode

这样就可以实时的获取子进程的输出。

一次获取子程序的全部输出

当你希望在子程序执行完后一次性获取所有子进程输出时,子进程对象可以调用communicate(),他会一直阻塞,等待子进程结束后获取子进程返回的输出。

ps = subprocess.Popen(args,stdout=subprocess.PIPE)
psAllReturn = ps.communicate()
#Or: psReturn = ps.stdout.read()
return psReturn

只有当子程序执行结束的后才会返回执行结果。
注意:communicate()会在通信一次之后即关闭了管道。如果希望进程之间频繁的通信,并不建议这种方法。
可以尝试下面的方法:

p= subprocess.Popen(["wc"], stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
p.stdin.write('your command')   #传递数据给子进程
p.stdin.flush()                 #清空子进程管道缓存
#......do something
try:  #......do something  p.stdout.readline()         #获取子进程输出#......do something
except:  print('IOError')  #......do something more  p.stdin.write('your other command')
p.stdin.flush()
#......do something more 

将标准错误和标准输出一起输出

ps = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)

这样无论是标准输出还是标准错误输出都会经过stdout管道返回给父进程。

shell

The shell argument (which defaults to False) specifies whether to use the shell as the program to execute. If shell is True, it is recommended to pass args as a string rather than as a sequence.
shell指定是否使用shell程序来执行子进程,当shell = True时,子进程将会由shell来执行,并且建议args参数使用String对象。
If args is a string, the string specifies the command to execute through the shell.

In [19]: p = subprocess.Popen("ipconfig /all",stdout = subprocess.PIPE,shell=True)  #args = "ipconfig /all"In [20]: pRet = p.stdout.read()  #父进程获得执行结果#On Windows with shell=True, the COMSPEC environment variable specifies the default shell.
#Win下相当于```args = ["cmd.exe","ipconfig","/all"]

On POSIX with shell=True, the shell defaults to /bin/sh.
Linux下相当于args = ["/bin/sh"," -c",args[0], args[1], ...]

bufsize

bufsize will be supplied as the corresponding argument to the open() function when creating the stdin/stdout/stderr pipe file objects.
0 means unbuffered (read and write are one system call and can return short)
1 means line buffered (only usable if universal_newlines=True i.e., in a text mode)
any other positive value means use a buffer of approximately that size
negative bufsize (the default) means the system default of io.DEFAULT_BUFFER_SIZE will be used.
当你将stdin/stdout/stderr重定向到PIPE或文件对象时,bufsize能够传递指定缓冲的方式给open()函数,并以此来创建文件对象:
0 表示无缓冲;
1 表示行缓冲;
otherNumber 表示缓冲区大小,
-1 是bufsize参数的缺省值表示使用系统缓冲(全缓冲)
注意:当子进程返回的数据达到缓存的Size时,子程序会等待付进程读取缓存数据。

close_fds

If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (POSIX only). The default varies by platform: Always true on POSIX. On Windows it is true when stdin/stdout/stderr are None, false otherwise. On Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.
在Unix中,如果close_fds = True,除了0、1、2之外的文件描述符都会被关闭。如果在Windows中stdin/stdout/stderr = None,即继承父进程时,close_fds = True ,相反为False。在Windows下也不会继承其他文件描述符。
注意:在Windows中不能够在close_fds = True的前提下对stdin, stdout or stderr做重定向(redirect ),锁定子进程的stdin/stdout/stderr。

In [24]: p = subprocess.Popen("ipconfig",shell=True,close_fds=True,stdout=subprocess.PIPE)ValueError: close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr

其他参数含义

given, startupinfo:If given, startupinfo will be a STARTUPINFO object, which is passed to the underlying CreateProcess function. creationflags, if given, can be CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP. (Windows only)
在Windows中,调用CreateProcess()函数创建子进程时,startupinfo参数会传递STARTUPINFO对象,来设置子进程的外观等等属性。

executable:指定要执行的程序名,很少使用,一般用args参数来指定需要执行的子程序。可以指定执行子进程的shell(e.g. bash、csh、zsh)。Unix下,默认是/bin/sh。Windows下,就是环境变量%COMSPEC%的值。windows下,只有当你要执行的命令确实是shell内建命令(比如dir ,copy)时,你才需要指定shell=True
,而当你要执行一个基于命令行的批处理脚本的时候,不需要指定此项。

C:\Users\Username>echo %COMSPEC%
C:\WINDOWS\system32\cmd.exe

preexec_fn:If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. (POSIX only)
钩子函数,只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用。容易造成死锁,慎用。

cmd:指定了子进程的工作目录
注意:并不会把该目录做为可执行文件的搜索目录,所以不要把子程序文件所在目录设置为cwd 。

env:是一个字典类型,用于执行子进程的执行环节变量,而不使用默认继承父进程的环境变量

universal_newlines:为True时,子进程的stdout和stderr被视为文本对象,不管是Unix的行结束符’/n’,还是Mac格式的行结束符’/r’,还是Windows格式的行结束符’/r/n’都将被视为 ‘/n’处理 。

pass_fds:is an optional sequence of file descriptors to keep open between the parent and child. Providing any pass_fds forces close_fds to be True. (POSIX only)

restore_signals:If restore_signals is true (the default) all signals that Python has set to SIG_IGN are restored to SIG_DFL in the child process before the exec. Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. (POSIX only)

start_new_session:If start_new_session is true the setsid() system call will be made in the child process prior to the execution of the subprocess. (POSIX only)

Popen成员函数

Popen.poll()

Check if child process has terminated. Set and return returncode attribute.
用于检查子进程是否已经结束。设置并返回returncode属性

Popen.wait(timeout=None)

Wait for child process to terminate. Set and return returncode attribute.
等待子进程结束。设置并返回returncode属性。使用Popen类创建的子进程时,父进程默认不会等待子进程结束,需要Call wait()函数来实现等待子进程结束后父进程继续执行。
timeout:If the process does not terminate after timeout seconds, raise a TimeoutExpired exception. It is safe to catch this exception and retry the wait.
注意: 如果子进程输出了大量数据到stdout或者stderr的管道,并达到了系统PIPE的缓存大小时,子进程会等待父进程读取管道内的数据,若此时父进程正在wait()的话,将不会读取管道内的数据,从而造成死锁,建议使用Pepon.communicate()来避免这种情况。

Popen.communicate(input=None,timeout=None)

与子进程进行交互。向stdin发送数据,可选参数input指定发送到子进程的数据。
Communicate()时从stdout和stderr中读取数据,直到文本末尾的EOF(进程之间采用文本通信),等待子进程结束。返回一个元组:(stdout_data, stderr_data),The data will be bytes or, if universal_newlines was True, strings.如果universal_newlines = True则返回一个String。
注意:如果希望通过stdin向子进程发送数据,需要通过stdin=PIPE创建管道对象。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。

p=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
(stdout_data, stderr_data) = p.communicate()

Note:If the process does not terminate after timeout seconds, a TimeoutExpired exception will be raised. Catching this exception and retrying communication will not lose any output.
如果timeout还没有结束进程的话,需要捕捉触发的TimeoutExpired异常,并且使用Popen.communicate()来保留子程序的输出。

proc = subprocess.Popen(...)
try:outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:proc.kill()outs, errs = proc.communicate()

Popen.send_signal(signal)

向子进程发送信号。

Popen.terminate()

停止子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。

Popen.kill()

杀死子进程,在Windows上调用了TerminateProcess() API。在Unix上相当于发送了信号SIGTERM和SIGKILL。

Popen成员属性

Popen.pid

获取子进程的进程ID。

Popen.returncode

获取进程的返回值。如果进程还没有结束,返回None。

Popen.stdin

If the stdin argument was PIPE, this attribute is a writeable stream object as returned by open()

输入交互

#test.py
import sys
line = sys.stdin.readline()
print 'test',line  #run.py
from subprocess import *
p = Popen('./test.py',stdin=PIPE,stdout=PIPE)
p.stdin.write('say hi/n')
print p.stdout.readline()  

Popen.stdout

If the stdout argument was PIPE, this attribute is a readable stream object as returned by open().

连续的输入输出交互

# test.py
import sys
while True:  line = sys.stdin.readline()  if not line:break  sys.stdout.write(line)  sys.stdout.flush()  # run.py
import sys
from subprocess import *
proc = Popen('./test.py',stdin=PIPE,stdout=PIPE,shell=True)
for line in sys.stdin:  proc.stdin.write(line)  #子进程的输入proc.stdin.flush()      output = proc.stdout.readline()    #子进程的输出  sys.stdout.write(output)           #父进程的打印

注意: run.py的flush和test.py中的flush,要记得清空缓冲区,否则程序得不到正确的输入和输出

Popen.stderr

If the stderr argument was PIPE, this attribute is a readable stream object as returned by open().

subprocess函数

subprocess函数本质上是对subprocess.Popen的封装,能够简便的创建子进程。当需要创建更加复杂的子进程时,建议使用Popen类,该类会生成子进程对象,且拥有多样化的成员方法和属性。

subprocess.call()

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

父进程等待子进程完成
返回退出信息(returncode,相当于Linux exit code)

In [20]: subprocess.call("ipconfig")
.
.
Out[20]: 0

subprocess.check_call()

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

父进程等待子进程完成
返回0
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性,可用try…except…来检查

In [25]: subprocess.check_call("config",shell=True)CalledProcessError: Command 'config' returned non-zero exit status 1

call()和check_call()的区别:两者的区别在于遇到错误的时候处理不一样,call()返回returncode ,check_call()再返回returncode后还会抛出异常。check_call实际上会调用call函数,然后加入了异常处理的情况。两者在本质上都会调用Popen().wait()来等待进程结束并返回returncode

subprocess.check_output()

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

父进程等待子进程完成
返回子进程向标准输出的输出结果
检查退出信息,如果returncode不为0,则举出错误subprocess.CalledProcessError,该对象包含有returncode属性和output属性,output属性为标准输出的输出结果,可用try…except…来检查。

最后

在使用subprocess模块的时候很容易卡死的情况出现,一些避免卡死的思路,我们之后再聊。 : -)

Python Module_subprocess_子进程(程序调用)相关推荐

  1. python c 语言接口,## 人生苦短我用python[0x08] 使用ctypes调用c语言接口 ##

    文章内容为原创,欢迎转载请注明出处 作者: EflyPro->晦明禅师 1.背景 python作为解析语言大规模应用在各个领域,c语言作为系统级别的语言广泛应用在基础,系统,网络等底层服务当中, ...

  2. python获取子进程返回值_Python 从subprocess运行的子进程中实时获取输出的例子 Python如何抓取程序的输出?...

    关于python中用subprocess调用exe子进程的问题不懂我的人有什么资格对我指指点点,不了解我的人凭什么对我说三道四的. python杀死子进程后继续执行后面程序 程序a(python写成) ...

  3. python脚本编程实例_C程序调用Python脚本的例子

    下面我们一起来看看关于C程序调用Python脚本的例子,如果你对此有兴趣的希望此教程对各位同学会有所帮助. 代码如下 复制代码 #include int main(){ PyObject * g_pM ...

  4. linux c 调用python_C程序调用Python脚本

    一般调用步骤 Py_Initialize(); //初始化Python环境 PyImport_ImportModule("test"); // 载入python模块 PyObjec ...

  5. python装饰器怎么调用_Python学习22-外部程序的调用装饰器

    调用外部程序 python是粘合语言 现成的工具软件,它们都可以完成一些功能(wget,ffmpeg)ffmpeg 用于win上录制视屏 有时需要扩展以下,添加一点功能(free)free Linux ...

  6. java程序员的开发Python游戏自动化脚本(调用大漠插件)系列(二)java?

    前言 既然大家都调用大漠插件,那肯定是有原因的,咱也用.插件确定下来了,接下来就是开发语言了,易语言.C++基本卖外挂的都是这些语言,懂得都懂.python网上资源也很多,java?极其少.不过作为一 ...

  7. 编好的python程序在自己的电脑上供其他程序调用方法

    程序猿可能都有这样的经历:编写完成的python程序,在自己的pyhtonIDE或pycharm或adnaconda中运行很正常,但使用pyinstaller打包生成exe文件后,会有这样那样讲不清的 ...

  8. python协同过滤调用包_简单的python协同过滤程序实例代码

    本文研究的主要是python协同过滤程序的相关内容,具体介绍如下. 关于协同过滤的一个最经典的例子就是看电影,有时候不知道哪一部电影是我们喜欢的或者评分比较高的,那么通常的做法就是问问周围的朋友,看看 ...

  9. 快速掌握用python写并行程序

    目录 一.大数据时代的现状 二.面对挑战的方法 2.1 并行计算 2.2 改用GPU处理计算密集型程序 3.3 分布式计算 三.用python写并行程序 3.1 进程与线程 3.2 全局解释器锁GIL ...

最新文章

  1. Java学习总结:51(对象序列化)
  2. 2019,不可错过的NLP“高光时刻”
  3. 机器学习笔记:梯度下降
  4. 2018/3/18 noip模拟赛 20分
  5. AI应用开发实战(转)
  6. 用c写按键精灵脚本语言,按键精灵之插件编写
  7. HDFS常用Shell命令
  8. 网站开发综合技术 HTML
  9. 天翼杯大数据算法应用大赛感想
  10. parceljs 中文文档24小时诞生记
  11. java简历项目经验大全,不吃透都对不起自己
  12. 如何重置华为交换机初始密码?
  13. 聚类的方法、原理以及一般过程
  14. jdk安装包解压后如何安装(jdk下载安装)
  15. Python绘制双坐标图
  16. 浙江大学计算机考研最新,2017年浙江大学计算机考研复试分数线_浙江大学考研分数线...
  17. 台式计算机对比评测报告,高效稳定的办公之选-宏碁商祺X4270评测报告
  18. Beanshell解析json-解析简单复杂json数据
  19. laravel seeding
  20. java 统计文本中出现概率最高的10个字符串!!

热门文章

  1. mysql城市联动表怎么建_MVC4.0搭建的省市县三联动,包含数据库
  2. 交换机和路由器的区别_路由器与交换机的区别?
  3. css如何设置图转30度,使用CSS实现左右30度的摆钟
  4. python 传感器数据结构_Python常用的数据结构详解
  5. cmd装b专用代码_Python 用5行代码学机器学习—线性回归
  6. java mysql 自动提交_Mybatis的JDBC提交设置/关闭mysql自动提交------关于mysql自动提交引发的惨剧...
  7. 机器人第一次独立手术!最快55分钟缝合肠道,华裔教授带队研发,“结果显著优于外科医生”...
  8. 48万!百度推出全球最便宜RoboTaxi,赚钱能力2倍于人类网约车
  9. 量子位「MEET 2021智能未来大会」启动,邀智能科技企业共探明日行业新格局
  10. 谷歌花35元就“骗”走刷脸数据:黑人为主,霸王条款无限使用,为强化新手机能力...