检测TTY输出结束

1 投票
2 回答
1158 浏览
提问于 2025-04-15 19:22

你好,我正在写一个伪终端,它可以在一个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 个回答

0

对于像命令行这样的应用,输出不会结束,直到命令行本身结束。你可以使用 select.select() 来检查是否还有更多的输出在等待你,或者直接结束这个进程。

1

其实,你的输出并没有完成。因为你启动了 /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 中使用这个方法非常不理想。

撰写回答