我需要实现Python中的过滤器,它从Linux的命令行工具字典挑出特定的输出。 我需要:
- 获取一组单词从文件
- 查找每个单词:1)如果没有这个词包含,跳过它; 2)否则,如果它是一个动词,保存定义。
为了测试代码,我写了两个Python文件:
# name.py
import sys
while True:
print 'name => Q: what is your name?'
sys.stdout.flush()
name = raw_input()
if name == 'Exit':
break
print 'name => A: your name is ' + name
sys.stdout.flush()
# test.py
import subprocess
child = subprocess.Popen(r'python name.py',
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT,
shell = True)
commandlist = ['Luke\n', 'Mike\n', 'Jonathan\n', 'Exit\n']
for command in commandlist:
child.stdin.write(command)
child.stdin.flush()
output = child.stdout.readline()
print 'From PIPE: ' + output
while child.poll() is None:
print 'NOT POLL: ' + child.stdout.readline()
child.wait()
输出是
From PIPE: name => Q: what is your name?
From PIPE: name => A: your name is Luke
From PIPE: name => Q: what is your name?
From PIPE: name => A: your name is Mike
# these lines need to start with "From PIPE" ...
NOT POLL: name => Q: what is your name?
NOT POLL: name => A: your name is Jonathan
NOT POLL: name => Q: what is your name?
NOT POLL:
后来输出的过程中被读取while
循环,而不是for
循环中test.py
。 是什么原因?
由于需求,我每次都需要得到整个输出输入它的新命令。 这似乎是一个对话会议。 所以subprocess.communicate()
是没用的存在,因为它总是终止当前子进程。 如何实现这个需求呢?
其根本原因subprocess
坚持使用.communicate()
是因为否则发生死锁是可能的。 假设你写进程的标准输入,而过程写入其标准输出。 如果管道缓冲区填满,写操作将阻塞,直到读发生。 然后,你们都在等待对方,没有能够取得进展。 有几种方法来解决这个问题:
- 使用单独的线程。 指定一个标准输入,另一个到标准输出。 这样,如果一个管块,你还在维修等。
- 使用
select
复用在管道。 只有喉管,随时为您服务交互。 你也应该让O_NONBLOCK
使用管道fcntl
,所以你不小心填补了缓冲区。 正确使用,这样可以防止管道从不断阻止,所以你不能死锁。 这无法在Windows下工作 ,因为你只能做select
上的插座那里。
在特定情况下,问题是,每个两行子进程版画,你的父进程只读取一行。 如果传递的名字那么最终你的进程死锁操作系统管缓冲区已经被填满后,作为@Kevin解释 。
为了解决这个问题,只需添加第二child.stdout.readline()
写名字的子进程之前阅读的问题。
例如,这里的parent.py
脚本:
#!/usr/bin/env python
from __future__ import print_function
import sys
from subprocess import Popen, PIPE
child = Popen([sys.executable, '-u', 'child.py'],
stdin=PIPE, stdout=PIPE,
bufsize=1, universal_newlines=True)
commandlist = ['Luke', 'Mike', 'Jonathan', 'Exit']
for command in commandlist:
print('From PIPE: Q:', child.stdout.readline().rstrip('\n'))
print(command, file=child.stdin)
#XXX you might need it to workaround bugs in `subprocess` on Python 3.3
#### child.stdin.flush()
if command != 'Exit':
print('From PIPE: A:', child.stdout.readline().rstrip('\n'))
child.stdin.close() # no more input
assert not child.stdout.read() # should be empty
child.stdout.close()
child.wait()
产量
From PIPE: Q: name => Q: what is your name?
From PIPE: A: name => A: your name is Luke
From PIPE: Q: name => Q: what is your name?
From PIPE: A: name => A: your name is Mike
From PIPE: Q: name => Q: what is your name?
From PIPE: A: name => A: your name is Jonathan
From PIPE: Q: name => Q: what is your name?
代码工作,但它仍然是脆弱的,如果输出child.py
过程可能会改变,然后僵局可能重新出现。 许多来控制一个互动的过程问题被解决了pexpect
模块 。 另见在此评论链接的代码示例 。
我已经改变了child.py
到两个Python 2和3的工作:
#!/usr/bin/env python
try:
raw_input = raw_input
except NameError: # Python 3
raw_input = input
while True:
print('name => Q: what is your name?')
name = raw_input()
if name == 'Exit':
break
print('name => A: your name is ' + name)