Home  >  Article  >  Backend Development  >  Detailed explanation of Python3's use of subprocess to implement pipeline pipe interactive operation read/write communication methods

Detailed explanation of Python3's use of subprocess to implement pipeline pipe interactive operation read/write communication methods

高洛峰
高洛峰Original
2017-03-20 10:28:124249browse

Here we use the shell under Windows as an example:

 subprocess  *

To facilitate your understanding, we use a very simple piece of code to illustrate:

Detailed explanation of Python3s use of subprocess to implement pipeline pipe interactive operation read/write communication methods

You can see that we used Popen to instantiate a p, created the subroutine cmd.exe, and then we gave him Stdin (standard input stream) and Stdout (standard output stream);

Also used subprocess. PIPE as a parameter, this is a special value used to indicate that these channels are to be opened. (In Python3.5, the run() method was added for better operations)

Then we continue

Detailed explanation of Python3s use of subprocess to implement pipeline pipe interactive operation read/write communication methods

This information Does it look familiar? This is all the standard output of cmd!

Then these will be output:

Detailed explanation of Python3s use of subprocess to implement pipeline pipe interactive operation read/write communication methods

The information "echo Hellwworlds\r\n" we just wrote has been written, it seems It did work!

Note that we use p.stdin.flush() to refresh the input buffer, and the output information also needs a "\r\n", at least under Windows systems This must be done, otherwise just refreshing (p.stdin.flush) will be invalid;

What exactly did we do?


We successfully created the subroutine cmd.exe and wrote "echo Hellwworlds\r\n". Then cmd obtained and executed it, then returned to Hellwworlds. This is a very simple read Write interactions!

More advanced use

Now that we can simply read and write, let’s add some for and threading, the taste may be better~

#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()

Very good very good , guess what the output is?

Detailed explanation of Python3s use of subprocess to implement pipeline pipe interactive operation read/write communication methods

The reason why there are many line breaks is that the results returned by cmd have line breaks, and then the print output will add a line break, so two lines are changed. You can consider using sys.stdout .write to output, so that there is no additional newline

In this case, you can make a basic read and write, then let's start encapsulation.

Encapsulating Pipe


No more nonsense, just go to the code. If you really want to learn, please read it yourself carefully. Read the code.

Line 110

We have implemented all processes in one class, and can define three parameters, exit feedback function , ready feedback function and output feedback function.

# -*- 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 &#39;_flag&#39; not True!")  #还未准备好就退出


    def start(self):
        """ 开始线程 """
        self._thread.start()

    def destroy(self):
        """ 停止并销毁自身 """
        process.stdout.close()
        self._thread.stop()
        del self
       





if __name__ == &#39;__main__&#39;:   #那么我们来开始使用它吧
    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()

Output:

Detailed explanation of Python3s use of subprocess to implement pipeline pipe interactive operation read/write communication methods

You can see that our instructions are executed sequentially. Of course, the OS is also responsible for this.

So your extensible Pipe class should have been built, right?

A: The reason why I add the line number in front of this code is to prevent you from copying; because you may never understand what is going on here, but only know how to use it.

By the way:

It is best to refer to the official documents, which are already explained in great detail. subprocess.Popen.communicate may be more suitable for you, depending on what you want to do.

The above is the detailed content of Detailed explanation of Python3's use of subprocess to implement pipeline pipe interactive operation read/write communication methods. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn