繁体   English   中英

python子进程中的多个输入和输出通信

[英]Multiple inputs and outputs in python subprocess communicate

我需要做类似这篇文章的事情,但我需要创建一个可以多次给出输入和输出的子流程。 该帖子的接受答案有很好的代码......

from subprocess import Popen, PIPE, STDOUT

p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)    
grep_stdout = p.communicate(input=b'one\ntwo\nthree\nfour\nfive\nsix\n')[0]
print(grep_stdout.decode())

# four
# five

...我想继续这样:

grep_stdout2 = p.communicate(input=b'spam\neggs\nfrench fries\nbacon\nspam\nspam\n')[0]
print(grep_stdout2.decode())

# french fries

但是,唉,我收到以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/subprocess.py", line 928, in communicate
    raise ValueError("Cannot send input after starting communication")
ValueError: Cannot send input after starting communication

如果我理解正确的话,proc.stdin.write() 方法不能让你收集输出。 为正在进行的输入/输出保持线路开放的最简单方法是什么?

编辑:====================

看起来pexpect对我正在尝试做的事情pexpect是一个有用的库,但我无法让它工作。 这是对我的实际任务的更完整的解释。 我正在使用hfst来获取单个(俄语)单词的语法分析。 下面演示了它在 bash shell 中的行为:

$ hfst-lookup analyser-gt-desc.hfstol
> слово
слово   слово+N+Neu+Inan+Sg+Acc 0.000000
слово   слово+N+Neu+Inan+Sg+Nom 0.000000

> сработай
сработай    сработать+V+Perf+IV+Imp+Sg2 0.000000
сработай    сработать+V+Perf+TV+Imp+Sg2 0.000000

> 

我希望我的脚本能够一次获得一种形式的分析。 我试过这样的代码,但它不起作用。

import pexpect

analyzer = pexpect.spawnu('hfst-lookup analyser-gt-desc.hfstol')
for newWord in ['слово','сработай'] :
    print('Trying', newWord, '...')
    analyzer.expect('> ')
    analyzer.sendline( newWord )
    print(analyzer.before)

# trying слово ...
# 
# trying сработай ...
# слово
# слово слово+N+Neu+Inan+Sg+Acc 0.000000
# слово слово+N+Neu+Inan+Sg+Nom 0.000000
# 
# 

我显然误解了pexpect.before作用。 如何获得每个单词的输出,一次一个?

Popen.communicate()是一种辅助方法,它一次性将数据写入stdin并创建线程以从stdoutstderr提取数据。 它在完成写入数据后关闭stdin并读取stdoutstderr直到这些管道关闭。 您无法进行第二次communicate因为孩子在返回时已经退出。

与子进程的交互式会话要复杂得多。

一个问题是子进程是否甚至认识到它应该是交互式的。 在大多数命令行程序用于交互的 C 库中,从终端(例如,linux 控制台或“pty”伪终端)运行的程序是交互式的并经常刷新它们的输出,但那些通过 PIPES 从其他程序运行的程序是非交互并很少刷新它们的输出。

另一个是您应该如何在不死锁的情况下读取和处理stdoutstderr 例如,如果您阻止读取stdout ,但stderr填充了它的管道,则孩子将停止并且您被卡住。 您可以使用线程将两者都拉入内部缓冲区。

另一个是你如何处理一个意外退出的孩子。

对于像 linux 和 OSX 这样的“unixy”系统,编写pexpect模块来处理交互式子进程的复杂性。 对于 Windows,我所知道的没有好的工具可以做到这一点。

这个答案应该归功于@JFSebastian。 感谢您的评论!

以下代码得到了我的预期行为:

import pexpect

analyzer = pexpect.spawn('hfst-lookup analyser-gt-desc.hfstol', encoding='utf-8')
analyzer.expect('> ')

for word in ['слово', 'сработай']:
    print('Trying', word, '...')
    analyzer.sendline(word)
    analyzer.expect('> ')
    print(analyzer.before)

每当您想向进程发送输入时,请使用proc.stdin.write() 每当您想从进程中获取输出时,请使用proc.stdout.read() 构造函数的stdinstdout参数都需要设置为PIPE

HFST 具有 Python 绑定: https ://pypi.python.org/pypi/hfst

使用这些应该可以避免整个刷新问题,并且会为您提供一个比解析 pexpect 的字符串输出更清晰的 API。

从 Python REPL,你可以得到一些关于绑定的文档

dir(hfst)
help(hfst.HfstTransducer)

或阅读https://hfst.github.io/python/3.12.2/QuickStart.html

抢夺文档的相关部分:

istr = hfst.HfstInputStream('hfst-lookup analyser-gt-desc.hfstol')
transducers = []
while not (istr.is_eof()):
    transducers.append(istr.read())
istr.close()
print("Read %i transducers in total." % len(transducers))
if len(transducers) == 1:
  out = transducers[0].lookup_optimize("слово")
  print("got %s" % (out,))
else: 
  pass # or handle >1 fst in the file, though I'm guessing you don't use that feature

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM