GVKun编程网logo

Python- 从subprocess.communicate()读取流输入(python读取数据流)

35

本文的目的是介绍Python-从subprocess.communicate的详细情况,特别关注读取流输入的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解Python

本文的目的是介绍Python- 从subprocess.communicate的详细情况,特别关注读取流输入的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解Python- 从subprocess.communicate的机会,同时也不会遗漏关于LINUX inner-process communication、process.communicate和getche()失败、python - 强制输入()从不同的线程读取换行符并向前执行 编辑 - 使用 subprocess 模块、python commands 和 subprocess的知识。

本文目录一览:

Python- 从subprocess.communicate()读取流输入(python读取数据流)

Python- 从subprocess.communicate()读取流输入(python读取数据流)

我正在使用Python subprocess.communicate()从运行约一分钟的进程中读取stdout。

我该如何stdout以流方式打印出该流程的每一行,以便可以看到生成的输出,但仍然阻止该流程终止,然后再继续?

subprocess.communicate() 似乎一次给出所有输出。

答案1

小编典典

这是一个简单的示例(不检查错误):

import subprocessproc = subprocess.Popen(''ls'',                       shell=True,                       stdout=subprocess.PIPE,                       )while proc.poll() is None:    output = proc.stdout.readline()    print output,

如果ls结束太快,则while循环可能会在你读取所有数据之前结束。

你可以通过以下方式在stdout中捕获其余部分:

output = proc.communicate()[0]print output,

答案2

小编典典

要在子进程刷新其stdout缓冲区后逐行获取子进程的输出:

#!/usr/bin/env python2from subprocess import Popen, PIPEp = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1)with p.stdout:    for line in iter(p.stdout.readline, b''''):        print line,p.wait() # wait for the subprocess to exit

iter()用于在编写行后立即读取行,以解决Python 2中的预读错误。

如果子进程的stdout在非交互模式下使用块缓冲而不是行缓冲(这会导致输出延迟,直到子缓冲区已满或被子进程显式刷新),然后你可以尝试使用以下方式强制使用无缓冲输出 pexpect,pty模块或unbuffer,stdbuf,script公用事业,见问:为什么不直接使用管道(popen方法())?

这是Python 3代码:

#!/usr/bin/env python3from subprocess import Popen, PIPEwith Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1,           universal_newlines=True) as p:    for line in p.stdout:        print(line, end='''')

注意:与Python 2不同,Python 2照原样输出子进程的字节串。Python 3使用文本模式(使用locale.getpreferredencoding(False)编码对cmd的输出进行解码)。

LINUX inner-process communication

LINUX inner-process communication

进程间通讯方式

管道

管道是针对对本地计算机的两个进程之间的通信而设计的通信方式,管道建立后,实际获得两个文件描述符,一个读取另一个写入。最常见的IPC机制,通过PIPE系统调用。管道是单工的,数据只能向一个方向流动,需要双向通信时,需要建立起两个管道。管道的本质是内核中的缓存。

管道特性:

  1. 可以通过两个管道来创建一个双向的管道
  2. 管道是阻塞性的,当进程从管道中读取数据,若没有数据进程会阻塞
  3. 管道有大小限制,管道满再放则会报错
  4. 不完整管道
  • 当读一个写端已经关闭的管道时,在所有数据被读取后,read返回0,以表示到达了文件尾部
  • 如果写一个读端已经关闭的管道,刚产生信号SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则write返回-1,同时errno设置为EPIPE

管道的分类

匿名管道
  1. 在关系进程中进行(父进程各子进程,兄弟进程之间)
  2. 由PIPE系统调用
  3. 管道位于内核空间,其实是一块缓存
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/**
*Desc:扇形多线程之间管道通信
*author:xiao_dingo
*since:2018-03-07
*email:wwc0524@163.com
*/

char *cmd1[3] = {"/bin/cat","/etc/passwd",NULL};
char *cmd2[3] = {"/bin/grep","root",NULL};

int main(void){

        int fd[2];
        if(pipe(fd) < 0){
                perror("pipe error");
        }

        int i = 0;
        pid_t pid;
        for(;i < 2; i++){
                pid = fork();
                if(pid < 0){
                        perror("fork error");
                        exit(1);
                }else if(pid == 0){//child process

                        if(i == 0){
                                close(fd[0]);

                                //将标准输出重定向到管道的写端
                                if(dup2(fd[1],STDOUT_FILENO) != STDOUT_FILENO){
                                perror("dup2 error");
                                }
                                close(fd[1]);
                                if(execvp(cmd1[0],cmd1) < 0){
                                        perror("execvp error");
                                        exit(1);
                                }
                                break;
                        }
                        if(i == 1){
                                close(fd[1]);

                                //将标准输入重定向到管道的读端
                                if(dup2(fd[0],STDIN_FILENO) != STDIN_FILENO){
                                perror("dup2 error");
                                }       
                                close(fd[0]);
                                if(execvp(cmd2[0],cmd2) < 0){
                                        perror("execvp error");
                                        exit(1);
                                }
                                break;
                        }
                }else{//parent process
                        if(i == 1){
                                close(fd[0]);
                                close(fd[1]);
                                wait(NULL);
                                wait(NULL);
                        }
                }
        }
        exit(0);
}
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

/**
*Desc:不完整管道之间操作
*author:xiao_dingo
*since:2018-03-08
*email:wwc0524@163.com
*/

void sig_handler(int signo){
        if(signo == SIGPIPE){
                printf("sigpipe occured\n");
        }
}

void main(void){
        int fd[2];
        if(pipe(fd) < 0){
                perror("pipe error");
                exit(1);
        }
        pid_t pid;
        if((pid = fork()) < 0){
                perror("fork error");
                exit(1);
        }else if(pid > 0){//parent process
                sleep(5);
                close(fd[0]);
                if(signal(SIGPIPE,sig_handler) == SIG_ERR){
                        perror("signal sigpipe error");
                        exit(1);
                }
                char *s = "1234";
                if(write(fd[1],s,sizeof(s)) != sizeof(s)){
                        fprintf(stderr,"%s,%s\n",strerror(errno),(errno == EPIPE) ? "EPIPE" : ",UNKNOW");
                }
        }else{//child process
                close(fd[0]);
                close(fd[1]);
        }
}
命名管道(FIFO)
  1. 两个没有任何关系的进行之间通信可以通过命名管道进行数据传输,本质是内核中的一块缓存,在文件系统中以一个特殊的设备文件(管道文件)存在。在文件系统中的管道文件只有一个索引块存放文件路径,没有数据块,所有数据存放在内核中。
  2. 通过系统调用mkfifo创建
  3. 命名管道必须读和写同时打开,否则会进入阻塞
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char* pathname,mode_t mode);

消息队列

System v IPC对象(消息队列,共享内存和信号量)存在于内核中而不是文件系统中,由用户控制释放(用户管理IPC对象的生命周期),不像管道和释放由内核控制。IPC对象通过标识符来引用和访问,所有的IPC对象在内核空间有唯一标识ID,在用户空间的唯一标识称为Key

消息队列特性

  1. 消息队列是内核中的一个链表
  2. 用户进程将数据传输到内核后,内核重新添加一些如用户ID,组ID,读写进程的ID和优先集等相关信息后并打成一个数据包称为消息
  3. 允许一个或者多个进程往消息队列中写消息和读消息,但一个消息只能被一个进程读取,读取完毕就自动删除
  4. 消息队列具有一定的FIFO的特性,消息可以按照顺序发送到队列中,也可以几种不同的方式从队列中读取,消息队列在内核中用一个唯一的IPC标识ID表示
  5. 消息队列的实现包括创建和打开队列,发送消息,读取消息,控制消息队列四种操作
  6. linux 系统查看命令ipcs 删除ipcrm
#include <sys/msg.h>
int msgget(key_t key,int flag);//查询
int msgctl(int msgid,int cmd,struct msgid_ds *buf);//控制
int msgsnd(int magid,const void *ptr,szie_t nbytes,int flag);//发送
ssize_t msgrvc(int msgqid,void *ptr,size_t nbytes,long type,int flag);//接收

共享内存

共享内存允许系统内两个或多个进程共享同一块内存空间,并且数据不用在客户进程和服务器进程间复制,因此共享内存是通信速度最快的一种IPC。
实现的机制简单描述如下:一个进程在系统中申请开辟了一块共享内存空间,然后使用这个共享内存空间的各个进程分别打开这个共享内存空间,并将这个内存空间映射到自己的进程空间上,这样各个进程就可以共同使用这个共享内存空间,就如同使用自己进程地址空间的内存一样
要实现共享内存空间,内核做了许多工作:比如给每个共享内存块分发一个“身份证”、允许用户进程将共享内存映射到各自的地址空间上、在进程提出申请以后将共享内存和进程地址空间脱离,并在适当的时候讲共享内存删除,让其回到可以被创建的状态。
用户利用共享内存实现进程间的通信,实际上就是使用内核提供的服务完成对共享内存的建立、映射、脱离、删除等。当建立并映射成功以后,进程间就能通过共享内存实现数据的交互。

内核提供的服务

/**
*shmget实现共享内存的建立或者打开
*当共享内存的键值key 尚未存在时,调用这个函数并且指定shmflg 参数为IPC_CREAT 可以创建一个大小为 size 的共享内存空间。假设key指定的共享内存已经存在,调用这个函数可以打开这个共享内存,但不会创建。
*
*/
int shmget(key_t key, size_t size, int shmflg);
/**
*该函数将一个共享内存空间映射到调用进程的地址空间上,并且返回在进程地址空间中的地址。用户拿到改地址后就可以通过这个地址间接的访问共享内存。
*shmid 参数就是shmget 函数的返回值,shmaddr 参数实际上是指出了共享内存映射到进程地址空间上的位置,但是我们一般不会指定这个地址,而是令其为NULL ,让内核选择一个合适的地址。shmflg 参数是配合着shmaddr 参数使用的,在shmaddr 为NULL时就变得没有实际意义,因此通常指定为0
*/
void *shmat(int shmid,const void* shmaddr,int shmflg);
/**
*这个函数将一个进程已经映射了的共享内存脱离进程地址空间。shmaddr 参数就是在进程地址空间的地址,实际就是shmat 函数的返回值
*/
int shmdt(const void* shmaddr);
/**
*此函数实际上有很多的功能,但是我们通长用它将一个已经创建了的共享内存删除,所谓删除实际就是将它放回可以被创建的共享内存队列中。指定cmd 参数为IPC_RMID,就可以将shmid键值指定的共享内存删除,而buf实际上是可以获取这共享内存在内核中的状态,如果不想了解可以指定为0
*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

进程信号量

用于进程间的huchi与同步,每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对所有信息量一次性操作,对信号量集中所有操作可以要求全部成功,也可以部分成功。
它是一个特殊变量,只允许对它进行等待和发送信号这两种操作。

  • P(信号量变量sv):等待。如果sv大于0,减小sv。如果sv为0,挂起这个进程的执行。
  • V(信号量变量sv):发送信号。如果有进程被挂起等待sv,使其恢复执行。如果没有进行被挂起等待sv,增加sv。
#include  <sys/sem.h>
/**
*
*
*/
int semget(key_t key,int nsems,int semflg);

process.communicate和getche()失败

process.communicate和getche()失败

我正在尝试自动执行用C ++编写的交互式命令行工具。

启动时,二进制等待字母S,Q或P(状态,退出或暂停)。 它使用一个非标准的msvcrt函数“getche”来获取关键笔划(而不是一个gets()例如),而用户不必敲击input。

我尝试以标准的方式与进程进行通信(写入stdin并使用process.communicate []),但是没有得到input。 经过几个小时的尝试不同的事情,我在Visual Studio中创build了两个小的示例项目来复制这个问题,并确保我是正常的(ish)。

这是用来调用二进制文件的python脚本:

Pythonsubprocess在返回输出之前在后台运行

一起使用gevent和multiprocessing与subprocess通信

Django的+ Apache + Windows WsgiDaemonProcess替代

Python运行Popen()subprocess与提升的UAC权限

Windows python脚本运行服务器并继续

import subprocess import time cmd = ["test-getch.exe"] process = subprocess.Popen(cmd,stderr = subprocess.PIPE,stdin = subprocess.PIPE,stdout = subprocess.PIPE) i = process.stdin #msvcrt.ungetch(''s'') i.write("Sn") print process.communicate()[0] i.close() time.sleep(3) print "DONE"

这是两个二进制文件。 这第一个我可以沟通:

#include "stdafx.h" #include <conio.h> int _tmain(int argc,_TCHAR* argv[]) { char response [2]; printf("Enter "s":n"); gets(response); printf("You entered %s",response); return 0; }

这一个我不能沟通:

#include "stdafx.h" #include <conio.h> int _tmain(int argc,_TCHAR* argv[]) { int response; printf("Enter "a":n"); response = getche(); printf("You entered %c",response); return 0; }

看来,getche()不会听stdin,可能会听某种键盘事件。 任何人都知道如何处理这个?

编辑:我也应该提到我发现了使用IDA Pro捕获input的方法。 我没有写我试图自动化的原始二进制文件。 这是一个封闭的源代码工具,所以我没有办法重写它如何接受input,而不修补二进制文件。

我实际上select了一个相当疯狂的解决scheme…我知道pydbg相当好,似乎附加到过程,并通过过程仪表调用我需要的function。 这完全是过分的,但我可以从这个过程中分离出来。 并使其正常运行。

[1] Pydbg: http ://pedram.redhive.com/PyDbg/docs/

Subprocess.call或Subprocess.Popen不能使用PATH(Linux / Windows)中的可执行文件

Python,Quickly和Glade,在TextView中显示stdout

将SIGINT信号委派给subprocess,然后清理并终止父进程

如何在Python中使用subprocess模块来启动和停止Linux程序?

删除2级子文件夹,但保留1级子文件夹

getche从控制台读取,而不是从标准输入读取。 如果您的Python进程正在控制台窗口中运行,那么您的子进程将仍然尝试从同一个控制台读取输入,而不是作为标准输入传入的管道。

可能会创建另一个不可见的控制台窗口,将其附加到子进程,并为其提供输入,但这非常复杂且容易出错。

我建议,而不是只重写您的程序只读取标准输入,而不是使用getche() 。 如果你真的想让它对按键做出反应,而不需要用户按Enter键,那么我建议让它根据标准输入是否来自终端来改变它的行为。 如果是,请使用getche ,如果不是,则直接从stdin读取。 您可以使用_isatty (或POSIX等效的isatty ;由于某些原因,Microsoft决定在其运行时中弃用POSIX名称)进行测试。 例如:

int ReadChar() { if(_isatty(0)) { // stdin is a terminal return _getche(); } else { // stdin is not a terminal return getchar(); } }

如果可以修改被调用程序的行为,Adam Rosenfield的答案是一个明智的方法。 否则,如果您确实需要写入控制台输入缓冲区,请尝试PyWin32的win32console模块。 这就是说,我不知道如何获得标准输出时,字符回声部分正常工作。 它最终打印到行的开始。

C:

#include <stdio.h> int main(int argc,char *argv[]) { int response; printf("Enter "a": "); response = getche(); printf("nYou entered "%c" ",response); return 0; } /* gcc test_getch.c -o test_getch.exe */

蟒蛇:

import subprocess import win32console def make_buf(c): buf = win32console.PyINPUT_recordtype(win32console.KEY_EVENT) buf.KeyDown = 1 buf.RepeatCount = 1 buf.Char = c return buf con_in = win32console.GetStdHandle(win32console.STD_INPUT_HANDLE) cmd = ["test_getch.exe"] p = subprocess.Popen(cmd,stdin=subprocess.PIPE) buf = make_buf(''a'') con_in.WriteConsoleInput([buf])

总结

以上是小编为你收集整理的process.communicate和getche()失败全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

python - 强制输入()从不同的线程读取换行符并向前执行 编辑 - 使用 subprocess 模块

python - 强制输入()从不同的线程读取换行符并向前执行 编辑 - 使用 subprocess 模块

在您的第一段代码中,您正在写入 sys.stdout,默认情况下不会影响 sys.stdin 的内容。此外,默认情况下,您不能直接写入 sys.stdin,但您可以将其更改为不同的文件。为此,您可以使用 os.pipe(),它将返回一个用于从新管道读取的文件描述符和一个用于写入管道的文件描述符的元组。

然后我们可以在这些文件描述符上使用 os.fdopen,并将 sys.stdin 分配给管道的读取端,而在另一个线程中我们写入管道的另一端。

import sys
import os
from threading import Thread

fake_stdin_read_fd,fake_stdin_write_fd = os.pipe()
fake_stdin_read = os.fdopen(fake_stdin_read_fd,'r')
fake_stdin_write = os.fdopen(fake_stdin_write_fd,'w')
sys.stdin = fake_stdin_read

def kill_input():
    fake_stdin_write.write('hello\n')
    fake_stdin_write.flush()

thread = Thread(target=kill_input)
thread.start()

input()
print('input() method has been bypassed!')

python commands 和 subprocess

python commands 和 subprocess

在Python 2中,经常使用commands模块来执行shell的命令,尤其是常用getstatusoutput()函数。 但是Python3中已经没有commands模块了,那么在Python 3中如果要调用一个命令,如何做呢?使用subprocess模块

import commands import subprocess

shell_commands = ''sar 1 3|grep "^平均时间:"'' status,result = commands.getstatusoutput(shell_commands) print(status,result) -------->(0, ''\xe5\xb9\xb3\xe5\x9d\x87\xe6\x97\xb6\xe9\x97\xb4: all 3.42 0.00 1.49 0.00 0.00 95.10'') print(type(commands.getstatusoutput(shell_commands))) --------><type ''tuple''> print(result.split()[2:]) # 取得cpu各个指标的值 -------->[''3.19'', ''0.00'', ''0.86'', ''0.09'', ''0.00'', ''95.87'']

result = subprocess.Popen(shell_command,shell=True,stdout=subprocess.PIPE) print(result) --------><subprocess.Popen object at 0x7fcd59974810> print(result.stdout.read()) -------->平均时间: all 3.05 0.00 0.85 0.00 0.00 96.10 print(type(result.stdout.read())) --------><type ''str''> print(result.stdout.read().split()[2:]) # 取得cpu各个指标的值 -------->[''9.54'', ''0.00'', ''1.39'', ''0.17'', ''0.00'', ''88.90'']

今天的关于Python- 从subprocess.communicate读取流输入的分享已经结束,谢谢您的关注,如果想了解更多关于LINUX inner-process communication、process.communicate和getche()失败、python - 强制输入()从不同的线程读取换行符并向前执行 编辑 - 使用 subprocess 模块、python commands 和 subprocess的相关知识,请在本站进行查询。

本文标签: