python 子进程中的多个输入和输出进行通信
Multiple inputs and outputs in python subprocess communicate
我需要做类似 this post 的事情,但我需要创建一个可以多次提供输入和输出的子流程。 post 的公认答案具有良好的代码...
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() 方法不能让您收集输出,如果我理解正确的话。保持线路畅通的最简单方法是什么 input/output?
编辑:====================
看起来 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
的作用。我怎样才能得到每个单词的输出,一次一个?
只要您想向进程发送输入,请使用 proc.stdin.write()
。每当您想从过程中获取输出时,请使用 proc.stdout.read()
。构造函数的 stdin
和 stdout
参数都需要设置为 PIPE
.
Popen.communicate()
是一种辅助方法,它执行 one-time 数据写入 stdin
并创建线程以从 stdout
和 stderr
中提取数据。它在完成写入数据时关闭 stdin
并读取 stdout
和 stderr
直到这些管道关闭。您不能执行第二个 communicate
,因为 child 在 returns 时已经退出。
具有 child 进程的交互式会话要复杂得多。
一个问题是 child 进程是否认识到它应该是交互式的。在大多数命令行程序用于交互的 C 库中,来自终端(例如,linux 控制台或 "pty" pseudo-terminal)的程序 运行 是交互的并经常刷新它们的输出,但是通过 PIPES 来自其他程序的那些 运行 是 non-interactive 并且不经常刷新它们的输出。
另一个是您应该如何阅读和处理 stdout
和 stderr
而不会出现死锁。例如,如果您阻止读取 stdout
,但 stderr
填充其管道,则 child 将停止并且您被卡住了。您可以使用线程将两者拉入内部缓冲区。
还有一个是如何处理 child 意外退出。
对于 "unixy" 系统,如 linux 和 OSX,编写 pexpect
模块是为了处理交互式 child 过程的复杂性。对于 Windows,据我所知没有好的工具可以做到这一点。
此回答应归于@J.F.Sebastian。感谢评论!
以下代码得到了我预期的行为:
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)
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
我需要做类似 this post 的事情,但我需要创建一个可以多次提供输入和输出的子流程。 post 的公认答案具有良好的代码...
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() 方法不能让您收集输出,如果我理解正确的话。保持线路畅通的最简单方法是什么 input/output?
编辑:====================
看起来 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
的作用。我怎样才能得到每个单词的输出,一次一个?
只要您想向进程发送输入,请使用 proc.stdin.write()
。每当您想从过程中获取输出时,请使用 proc.stdout.read()
。构造函数的 stdin
和 stdout
参数都需要设置为 PIPE
.
Popen.communicate()
是一种辅助方法,它执行 one-time 数据写入 stdin
并创建线程以从 stdout
和 stderr
中提取数据。它在完成写入数据时关闭 stdin
并读取 stdout
和 stderr
直到这些管道关闭。您不能执行第二个 communicate
,因为 child 在 returns 时已经退出。
具有 child 进程的交互式会话要复杂得多。
一个问题是 child 进程是否认识到它应该是交互式的。在大多数命令行程序用于交互的 C 库中,来自终端(例如,linux 控制台或 "pty" pseudo-terminal)的程序 运行 是交互的并经常刷新它们的输出,但是通过 PIPES 来自其他程序的那些 运行 是 non-interactive 并且不经常刷新它们的输出。
另一个是您应该如何阅读和处理 stdout
和 stderr
而不会出现死锁。例如,如果您阻止读取 stdout
,但 stderr
填充其管道,则 child 将停止并且您被卡住了。您可以使用线程将两者拉入内部缓冲区。
还有一个是如何处理 child 意外退出。
对于 "unixy" 系统,如 linux 和 OSX,编写 pexpect
模块是为了处理交互式 child 过程的复杂性。对于 Windows,据我所知没有好的工具可以做到这一点。
此回答应归于@J.F.Sebastian。感谢评论!
以下代码得到了我预期的行为:
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)
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