管道输入到另一个可执行文件并从中读取输出
pipe input to and read output from another executable
我想写一个脚本,它的工作方式有点像 hadoop 流式传输:我提供一个随机的 "client" 程序路径,并从我的主机 python 脚本我 "pipe" 字符串到客户端,我想在我的 python 程序中接收客户端的标准输出。
例如,如果我有以下 python 基本 python 客户端 "client.py":
import sys
for line in sys.stdin:
print("printing : " + line)
我想从我的 python 主机调用可执行文件 "python client.py",为它提供列表 ["a", "b"]
,然后接收 ["printing a", "printing b"]
作为结果。
这是我在主机代码中尝试的内容:
import subprocess
proc = subprocess.Popen("python client.py",stdout=subprocess.PIPE, stdin=subprocess.PIPE)
for text in ["a", "b"]
print(text)
proc.stdin.write(bytes(text, 'UTF-8'))
result = proc.stdout.read()
print ("result " + str(result))
self.proc.wait()
但是(在 windows 上)它执行 print(text)
,然后打开一个保持冻结状态的 python.exe windows....
有谁知道如何完成我想要做的事情?理想情况下应该在 windows 和 linux 上工作
编辑:在我的实际应用程序中,传输到 stdin 的数据量为 10000 行,每行约 1K 个字符,所以我不能一次发送所有数据
来自 stdout 的内容应该是大约 10000 行,每行 10 个字符
为了与子进程交互(例如,读取 'prompts' 并对它们做出反应)pexpect 是要走的路:
https://pexpect.readthedocs.org/en/stable/
但是,如果您不关心交互 "intelligently" 并且只想发送一堆行并回显它们...
在client.py中:
from sys import stdin
for line in stdin:
print(line,end="")
并在您的主机文件中:
from subprocess import Popen, PIPE
text = b"a\nb\n"
sub = Popen(["python3","client.py"],stdout=PIPE,stdin=PIPE).communicate(text)
print(sub[0].decode())
根据您的编辑,请参阅下面的新主机文件:
import os
from pty import fork
from time import sleep
inputs = [b"a",b"b"]
parent, fd = fork()
if not parent:
os.execv("/usr/bin/python3",["usr/bin/python3","/path/to/file/client.py"])
for each in inputs:
os.write(fd,each+b'\n')
sleep(0.5)
os.read(fd,len(each)) #We have to get rid of the echo of our write
print(os.read(fd,200).decode().strip())
在客户端中使用与 Popen 一起使用的 sys.stdin 方法也存在问题,因为客户端启动时输入不存在,因此我们需要使其阻塞。一个(非常简单的)例子:
i = input()
print("printing {0}".format(i))
i = input()
print("printint {0}".format(i))
这不适用于 Windows(除非有人在那里分叉而我不知道)。我不确定如何在 windows 中执行此操作,因为我没有在那里度过时间。
这里有很大的局限性。它是同步的,一方面,os.read() 并不完全是高级别。
问题是 read()
试图读取整个流,这意味着它会一直等到子进程终止。您需要确定一种方法来了解角色何时可用。以下是一些方法:
- 一次读取一个字符,直到遇到 return 字符(行尾)。
- 子应用程序可以发送恒定长度的输出。可以在read方法中指定字符长度。
- 子应用程序可以宣布它将打印多少个字符。
您还需要一个条件来告诉子进程结束。例如,当它收到一个特殊的字符串时。
另一个问题可能来自缓冲:数据可能不会在写入操作后立即发送运行。在这种情况下,您可以使用flush()
来保证运行发球。
我知道你上面的代码在python3,但是为了避免unicode转换的问题,下面的程序在python2。将它们转换为 python3.
应该没有问题
计划client.py
# pyhton2
import sys
do_run = True
while do_run:
i = ''
line = ''
while i != '\n': # read one char at a time until RETURN
i = sys.stdin.read(1)
line += i
#
if line.startswith("END"):
do_run = False
else:
sys.stdout.write("printing : " + line) # RET already in line
sys.stdout.flush()
计划main.py
from subprocess import Popen, PIPE
proc = Popen(["python2","client.py"], stdout=PIPE, stdin=PIPE, stderr=PIPE )
for text in ('A', 'B', 'C', 'D', 'E'):
print text
proc.stdin.write(text+"\n")
proc.stdin.flush()
i = ''
result_list=[]
while i != '\n':
i = proc.stdout.read(1)
result_list.append(i)
print ("result " + "".join(result_list))
proc.stdin.write("END\n")
我 运行 在 Raspberry Pi (Rasbian) 上运行以下程序并且它有效。但是,如果我用 flush()
注释这些行,程序就会卡住。
这些程序使用第一个选项(一次读取一个字符),这可能是最慢的。您可以通过使用其他两个来提高速度,但代价是代码更复杂。
我想写一个脚本,它的工作方式有点像 hadoop 流式传输:我提供一个随机的 "client" 程序路径,并从我的主机 python 脚本我 "pipe" 字符串到客户端,我想在我的 python 程序中接收客户端的标准输出。
例如,如果我有以下 python 基本 python 客户端 "client.py":
import sys
for line in sys.stdin:
print("printing : " + line)
我想从我的 python 主机调用可执行文件 "python client.py",为它提供列表 ["a", "b"]
,然后接收 ["printing a", "printing b"]
作为结果。
这是我在主机代码中尝试的内容:
import subprocess
proc = subprocess.Popen("python client.py",stdout=subprocess.PIPE, stdin=subprocess.PIPE)
for text in ["a", "b"]
print(text)
proc.stdin.write(bytes(text, 'UTF-8'))
result = proc.stdout.read()
print ("result " + str(result))
self.proc.wait()
但是(在 windows 上)它执行 print(text)
,然后打开一个保持冻结状态的 python.exe windows....
有谁知道如何完成我想要做的事情?理想情况下应该在 windows 和 linux 上工作
编辑:在我的实际应用程序中,传输到 stdin 的数据量为 10000 行,每行约 1K 个字符,所以我不能一次发送所有数据 来自 stdout 的内容应该是大约 10000 行,每行 10 个字符
为了与子进程交互(例如,读取 'prompts' 并对它们做出反应)pexpect 是要走的路:
https://pexpect.readthedocs.org/en/stable/
但是,如果您不关心交互 "intelligently" 并且只想发送一堆行并回显它们...
在client.py中:
from sys import stdin
for line in stdin:
print(line,end="")
并在您的主机文件中:
from subprocess import Popen, PIPE
text = b"a\nb\n"
sub = Popen(["python3","client.py"],stdout=PIPE,stdin=PIPE).communicate(text)
print(sub[0].decode())
根据您的编辑,请参阅下面的新主机文件:
import os
from pty import fork
from time import sleep
inputs = [b"a",b"b"]
parent, fd = fork()
if not parent:
os.execv("/usr/bin/python3",["usr/bin/python3","/path/to/file/client.py"])
for each in inputs:
os.write(fd,each+b'\n')
sleep(0.5)
os.read(fd,len(each)) #We have to get rid of the echo of our write
print(os.read(fd,200).decode().strip())
在客户端中使用与 Popen 一起使用的 sys.stdin 方法也存在问题,因为客户端启动时输入不存在,因此我们需要使其阻塞。一个(非常简单的)例子:
i = input()
print("printing {0}".format(i))
i = input()
print("printint {0}".format(i))
这不适用于 Windows(除非有人在那里分叉而我不知道)。我不确定如何在 windows 中执行此操作,因为我没有在那里度过时间。
这里有很大的局限性。它是同步的,一方面,os.read() 并不完全是高级别。
问题是 read()
试图读取整个流,这意味着它会一直等到子进程终止。您需要确定一种方法来了解角色何时可用。以下是一些方法:
- 一次读取一个字符,直到遇到 return 字符(行尾)。
- 子应用程序可以发送恒定长度的输出。可以在read方法中指定字符长度。
- 子应用程序可以宣布它将打印多少个字符。
您还需要一个条件来告诉子进程结束。例如,当它收到一个特殊的字符串时。
另一个问题可能来自缓冲:数据可能不会在写入操作后立即发送运行。在这种情况下,您可以使用flush()
来保证运行发球。
我知道你上面的代码在python3,但是为了避免unicode转换的问题,下面的程序在python2。将它们转换为 python3.
应该没有问题计划client.py
# pyhton2
import sys
do_run = True
while do_run:
i = ''
line = ''
while i != '\n': # read one char at a time until RETURN
i = sys.stdin.read(1)
line += i
#
if line.startswith("END"):
do_run = False
else:
sys.stdout.write("printing : " + line) # RET already in line
sys.stdout.flush()
计划main.py
from subprocess import Popen, PIPE
proc = Popen(["python2","client.py"], stdout=PIPE, stdin=PIPE, stderr=PIPE )
for text in ('A', 'B', 'C', 'D', 'E'):
print text
proc.stdin.write(text+"\n")
proc.stdin.flush()
i = ''
result_list=[]
while i != '\n':
i = proc.stdout.read(1)
result_list.append(i)
print ("result " + "".join(result_list))
proc.stdin.write("END\n")
我 运行 在 Raspberry Pi (Rasbian) 上运行以下程序并且它有效。但是,如果我用 flush()
注释这些行,程序就会卡住。
这些程序使用第一个选项(一次读取一个字符),这可能是最慢的。您可以通过使用其他两个来提高速度,但代价是代码更复杂。