如果fd是bash shell,如何避免行缓冲问题?
答案 0 :(得分:1)
以下是我从您的问题和评论中理解的内容以及答案结尾处不满意的解决方法的摘要。摘要应该帮助其他人回答您的问题。
似乎你有一个程序(非python)想要执行可能需要tty(Q: Why not just use a pipe (popen())?)的任意shell命令,并且你已选择作为执行运行{{1写入/读取其stdin / stdout。
现在你遇到一个问题,你无法找到shell命令的输出结束,即,你不知道何时停止阅读pty.spawn("/bin/sh", read_callback)
标准输出,如果你试着阅读太多,那么你的非python程序块。
首先,program.py
中的os.read
不会阻止。它可能返回少于1024个字节,但它不会阻塞:
read_callback
虽然在父程序尝试阅读时没有帮助。
为避免阻止读取,父级可以将运行def read_callback(fd):
data = os.read(fd, 1024) # <-- this doesn't block
return data
中的PS1
环境更改为某个唯一值,或者在每个命令后注入sh
。然后它可以一次读取一个字节,直到它读取echo something_unique
。它应该停在这一点上。
作为替代方法,您可以尝试在父级中使管道非阻塞,并一次读取多个字节。或者使用定义明确消息边界的交换协议并逐个运行shell命令,例如,使用something_unique
(在Python端轻松检测输出结束)。
答案 1 :(得分:0)
这似乎有效:
#!/usr/local/cpython-3.3/bin/python
import os
import pty
#mport sys
import fcntl
OFLAGS = None
def set_nonblocking(file_handle):
"""Make a file_handle non-blocking."""
global OFLAGS
OFLAGS = fcntl.fcntl(file_handle, fcntl.F_GETFL)
nflags = OFLAGS | os.O_NONBLOCK
fcntl.fcntl(file_handle, fcntl.F_SETFL, nflags)
def main():
(pid, file_handle) = pty.fork()
if pid == 0:
# we're in the child
os.execl('/bin/sh', '/bin/sh', '-i')
else:
#file_handle = os.open('/dev/null', os.O_RDONLY)
set_nonblocking(file_handle)
while True:
try:
# return 1-n bytes or exception if no bytes
data = os.read(file_handle, 1024)
except BlockingIOError:
#sys.stdout.write('no data read\r')
pass
else:
print(len(data), data)
main()
有时处理非阻塞I / O的方法是使用线程或子进程,BTW。然后一个线程或子进程可以阻塞,而其他线程或子进程可以快乐地完成它们的工作。
HTH