这里我们用Windows下的shell来举例:

from subprocess import * #因为是举例,就全部导入了

为了方便你理解,我们用一个很简单的一段代码来说明:

可以看见我们利用Popen实例化了一个p,创建了子程序cmd.exe,然后我们给他的的Stdin(标准输入流)Stdout(标准输出流);

同时使用了subprocess.PIPE 作为参数,这个是一个特殊值,用于表明这些通道要开放。(在Python3.5,加入了run()方法来进行更好的操作)

然后我们继续

这些信息是不是很眼熟?这都是cmd的标准输出!

然后就会输出这些:

我们刚刚所写入的信息"echo Hellwworlds\r\n"已经被写入了,看起来确实成功了!

注意一下我们使用了 p.stdin.flush() 来对输入缓存区进行刷新,输出的信息也需要一个 "\r\n",至少在 Windows 系统下必须这样做,否则只刷新(p.stdin.flush)的话是无效的;

我们到底做了什么?


我们成功的创建了子程序 cmd.exe,并且写入"echo Hellwworlds\r\n" ,然后cmd获取了并且执行,于是返回 Hellwworlds,这就是一次很简单的读写交互!

更高级的使用


既然我们已经可以简单的读写了,那么加点for和threading 吧,味道也许更佳喔~

 #run.py  

 from subprocess import *
import threading
import time p =Popen('cmd.exe',shell=True,stdin=PIPE,stdout=PIPE) def run():
global p
while True:
line = p.stdout.readline()
if not line: #空则跳出
break
print(">>>>>>",line.decode("GBK")) print("look up!!! EXIT ===") #跳出 w =threading.Thread(target=run) p.stdin.write("echo HELLW_WORLD!\r\n".encode("GBK"))
p.stdin.flush()
time.sleep(1) #延迟是因为等待一下线程就绪
p.stdin.write("exit\r\n".encode("GBK"))
p.stdin.flush() w.start()

很好很好,猜猜输出什么?

有很多换行的原因是cmd返回的结果有换行,然后print输出会加一个换行,所以就换了两行,你可以考虑使用 sys.stdout.write 来输出,这样就没有附加的换行了

这样的话,你可以制作一个基础的读写了,那么我们开始封装吧。

封装Pipe


不废话了,直接上代码,如果你真的想学会的话,还请认真自己读读代码。

110行

我们实现了将所有的过程集中在一个类里面,并且可以定义三个参数,退出反馈函数,就绪反馈函数和输出反馈函数。

 # -*- coding:utf-8 -*-

 import subprocess
import sys
import threading class LoopException(Exception):
"""循环异常自定义异常,此异常并不代表循环每一次都是非正常退出的"""
def __init__(self,msg="LoopException"):
self._msg=msg def __str__(self):
return self._msg class SwPipe():
"""
与任意子进程通信管道类,可以进行管道交互通信
"""
def __init__(self,commande,func,exitfunc,readyfunc=None,
shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,code="GBK"):
"""
commande 命令
func 正确输出反馈函数
exitfunc 异常反馈函数
readyfunc 当管道创建完毕时调用
"""
self._thread = threading.Thread(target=self.__run,args=(commande,shell,stdin,stdout,stderr,readyfunc))
self._code = code
self._func = func
self._exitfunc = exitfunc
self._flag = False
self._CRFL = "\r\n" def __run(self,commande,shell,stdin,stdout,stderr,readyfunc):
""" 私有函数 """
try:
self._process = subprocess.Popen(
commande,
shell=shell,
stdin=stdin,
stdout=stdout,
stderr=stderr
)
except OSError as e:
self._exitfunc(e)
fun = self._process.stdout.readline
self._flag = True
if readyfunc != None:
threading.Thread(target=readyfunc).start() #准备就绪
while True:
line = fun()
if not line:
break
try:
tmp = line.decode(self._code)
except UnicodeDecodeError:
tmp = \
self._CRFL + "[PIPE_CODE_ERROR] <Code ERROR: UnicodeDecodeError>\n"
+ "[PIPE_CODE_ERROR] Now code is: " + self._code + self._CRFL
self._func(self,tmp) self._flag = False
self._exitfunc(LoopException("While Loop break")) #正常退出 def write(self,msg):
if self._flag:
#请注意一下这里的换行
self._process.stdin.write((msg + self._CRFL).encode(self._code))
self._process.stdin.flush()
#sys.stdin.write(msg)#怎么说呢,无法直接用代码发送指令,只能默认的stdin
else:
raise LoopException("Shell pipe error from '_flag' not True!") #还未准备好就退出 def start(self):
""" 开始线程 """
self._thread.start() def destroy(self):
""" 停止并销毁自身 """
process.stdout.close()
self._thread.stop()
del self if __name__ == '__main__': #那么我们来开始使用它吧
e = None #反馈函数
def event(cls,line):#输出反馈函数
sys.stdout.write(line) def exit(msg):#退出反馈函数
print(msg) def ready():#线程就绪反馈函数
e.write("dir") #执行
e.write("ping www.baidu.com")
e.write("echo Hello!World 你好中国!你好世界!")
e.write("exit") e = SwPipe("cmd.exe",event,exit,ready)
e.start()

输出:

你可以看见,我们的指令都顺序的执行了。当然了这里面还有OS的功劳。

那么你的可扩展的Pipe类应该已经构建完毕了吧?

A: 我之所以要在这种代码前面加入行数的原因就是为了防止你复制;因为你可能永远不会明白这里究竟发生了什么,而是只懂得了使用。

顺便一提:

最好去参考一下官方的文档,已经讲得非常详细了。subprocess.Popen.communicate 或许更适合你,看你是要进行什么事情。

参考:

https://docs.python.org/3/library/subprocess.html

到此结束,如有错误之处还望指正。

不论是否对你有帮助,感谢你耐心阅读

Python 3 利用 subprocess 实现管道( pipe )交互操作读/写通信的更多相关文章

  1. python 查找元素 获取元素信息 元素交互操作 执行JavaScript

    from selenium import webdriver browser = webdriver.Firefox() browser.get("https://tieba.baidu.c ...

  2. day9 python学习 文件的操作 读 写 seek

    文件的操作 1   文件的打开操作: 文件句柄 = open('文件路径', '模式') f=open('wangyakun','a+',encoding='utf-8') #文件名, 如果是绝对路径 ...

  3. python学习笔记——multiprocessing 多进程组件 Pipe管道

    进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...

  4. python学习之-- redis模块管道/订阅发布

    redis 模块操作剩余其他常用操作 delete(*names):删除任意的数据类型exists(name):检测redis的name是否存在keys(pattern='*'):根据模型获取redi ...

  5. Python的subprocess子进程和管道进行交互

    在很久以前,我写了一个系列,Python和C和C++的交互,如下 http://blog.csdn.net/marising/archive/2008/08/28/2845339.aspx 目的是解决 ...

  6. 【python】使用unix管道pipe处理stdout实时数据

    现在有个实时抓包处理的程序,大概的流程是 使用tshark抓包->实时上传,如果写log的话是可以的,但是log文件切割需要定时执行. 由于log中有些内容需要实时处理,延迟时间会导致数据误差, ...

  7. [b0037] python 归纳 (二二)_多进程数据共享和同步_管道Pipe

    # -*- coding: utf-8 -*- """ 多进程数据共享 管道Pipe 逻辑: 2个进程,各自发送数据到管道,对方从管道中取到数据 总结: 1.只适合两个进 ...

  8. python管道pipe

    1.什么是管道 Linux进程间通信方式的一种,管道有两端,读端和写端.创建管道,然后从父进程fork出子进程, 父进程和子进程拥有共同的读写文件描述符,可以实现子进程写文件,父进程读文件的操作. 示 ...

  9. python学习之-- subprocess模块

    subprocess 模块 功能:用来生成子进程,并可以通过管道连接它们的输入/输出/错误,以及获得它们的返回值.它用来代替多个旧模块和函数: os.system os.spawn* os.popen ...

随机推荐

  1. 搭建jekyll博客

    使用jekyll将markdown文件生成静态的html文件,并使用主题有序的进行布局,形成最终的博客页面. 特点 基于ruby 使用Markdown书写文章 无需数据库 可以使用GitHub Pag ...

  2. Java构造函数

    构造函数的定义: 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...

  3. iOS开发——高级语法篇&继承、实现、依赖、关联、聚合、组合的联系与区别

    继承.实现.依赖.关联.聚合.组合的联系与区别 分别介绍这几种关系: 继承 指的是一个类(称为子类.子接口)继承另外的一个类(称为父类.父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者 ...

  4. Java多线程synchronized同步

    非线程安全问题 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”.也即是说,方法中的变量永远是线程安全的. 如果多个线程共同访问1个对象中的实例变量,则可能线程 ...

  5. 初了解NodeJS

    发现了NodeJS以后让我有一种很激动的心情,因为它能做我以前一直想写的东西,而如果没有NodeJS我还需要去学习别的语言,但是有了NodeJS以后就可以通过Javascript来写我的程序了,不得不 ...

  6. WP中的语音识别(下):语音指令

    除了系统集成的可以用于搜索.启动应用程序等语音命令外,在我们的应用程序内部还能自己定义语音指令,使得我们的APP能与语音操控结合得更加完全. 语音指令是通过一个XML文件来定义的.比如,咱小舅子开了家 ...

  7. poj1330Nearest Common Ancestors 1470 Closest Common Ancestors(LCA算法)

    LCA思想:http://www.cnblogs.com/hujunzheng/p/3945885.html 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好 ...

  8. 借助 CSS Colorguard 来避免使用重复的颜色

    每一个 CSS 项目开始时愿望都是很美好的,但不可避免地,多人协作的项目相互之间可能重复使用了相似的颜色,而你从来不知道它们的存在.CSS Colorguard 帮助您保持您想要的颜色设置,当你添加的 ...

  9. nodejs 生产环境配置

    1.node 默认为development(开发)模式 启动node 时可以设置模式为生产模式 set NODE_ENV=production node app.js 2.设置node监听的端口 va ...

  10. MySQL(Navicat)运行.sql文件时报错:[Err] 2006 - MySQL server has gone away 的解决方法

    背景: 今天导入一个数据量很大的.sql文件时,报错: 原因: 可能是sql语句过长,超过mysql通信缓存区最大长度. 解决:1. 编辑 MySQL 安装目录下的 my.ini,在最后添加以下内容: ...