检测TTY输出结束
你好,我正在写一个伪终端,它可以在一个tty中运行,并且可以生成第二个tty,这个tty会过滤输入和输出。
现在我用Python来写这个程序,生成第二个tty并进行读写是很简单的。
但是当我读取数据时,读取操作不会结束,它会一直等待更多的输入。
import subprocess
pfd = subprocess.Popen(['/bin/sh'], shell=True,
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
cmd = "ls"
pfd.stdin.write(cmd + '\n')
out = ''
while 1:
c = pfd.stdout.read(1)
if not c: # if end of output (this never happends)
break
if c == '\n': # print line when found
print repr(out)
out = ''
else:
out += c
----------------------------- 输出 ------------------------
intty $ python intty.py
'intty.py'
'testA_blank'
'testB_blank'
(hangs here does not return)
看起来它达到了缓冲区的末尾,但不是返回None或空字符串,而是一直挂在那里等着更多的输入。
我应该关注什么来判断输出是否完成呢?是缓冲区的结束吗?还是某个不可打印的字符?
---------------- 编辑 -------------
当我运行xpcshell而不是ls时,这种情况也会发生。我猜这些交互式程序有某种方式来知道何时再次显示提示符,奇怪的是,在这种情况下,提示符“js>”从来没有出现过。
2 个回答
对于像命令行这样的应用,输出不会结束,直到命令行本身结束。你可以使用 select.select()
来检查是否还有更多的输出在等待你,或者直接结束这个进程。
其实,你的输出并没有完成。因为你启动了 /bin/sh
,所以在“ls”命令执行完后,shell 仍然在运行。没有结束标志,因为它还在运行中。
那为什么不直接运行 /bin/ls
呢?
你可以做一些类似这样的事情:
pfd = subprocess.Popen(['ls'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
out, err_output = pfd.communicate()
这也强调了 subprocess.communicate
,这是获取单个程序输出的更安全的方法(当然是针对那些能放进内存的输出)。这个方法会等到程序完全运行结束后才会返回结果。
另外,你也可以从 shell 中逐行读取输出,但你需要寻找一个特殊的 shell 序列,比如 sh~#
这一行,这可能会在程序输出中出现。因此,运行一个 shell 通常来说并不是个好主意。
编辑 这是我提到的内容,但这仍然不是最好的解决方案,因为它有很多限制:
while 1:
c = pfd.stdout.read(1)
if not c:
break
elif c == '\n': # print line when found
print repr(out)
out = ''
else:
out += c
if out.strip() == 'sh#':
break
请注意,如果其他命令在行首输出 'sh#',这个方法就会失效;而且如果输出和预期不同,你也会再次陷入之前的阻塞情况。这就是为什么在 shell 中使用这个方法非常不理想。