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

标签 python subprocess stdout stdin pexpect

我需要做类似 this 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() 方法不能让你收集输出。为正在进行的输入/输出保持线路畅通的最简单方法是什么?

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

看起来 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 并创建线程以从 stdout标准错误。它在完成写入数据时关闭 stdin 并读取 stdoutstderr 直到这些管道关闭。你不能做第二次 communicate 因为 child 在返回时已经退出了。

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

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

另一个是您应该如何读取和处理 stdoutstderr 而不会出现死锁。例如,如果您阻止读取 stdout,但 stderr 填充其管道,则子进程将停止,您将被卡住。您可以使用线程将两者拉入内部缓冲区。

还有一个问题是如何处理意外退出的 child 。

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

关于python - python子进程中的多个输入和输出进行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28616018/

相关文章:

python - 从 python 子进程模块启动模块 shell 命令

python:将标准输出选择性重定向到文件

javascript - 什么是 Django 端点?

python - Airflow :错误:无法识别的参数:网络服务器

python - 从两个坐标数组创建所有 x,y 对

python - 如何在带有子进程的 Python 中使用 mv 命令

python - 尝试失败时退出函数的最可靠方法

python - tail 命令没有给出 subprocess.Popen 的正确答案

linux - 为什么 Laravel Task Scheduler cron 使用 >> 而不是 > 重定向到 dev/null?

Python + ffmpeg 类型错误 : not all arguments converted during string formatting