首页 > 解决方案 > 取消缓冲时,Unix 脚本命令会中断终端

问题描述

抱歉标题很奇怪,也许有人可以改进它。

我在 Python 子进程中使用脚本命令来取消缓冲输出命令。然后我从该过程中读取了一行,最后我打印了一些文本。这是我的代码(此文件名为script.py):

import subprocess
import time

proc = subprocess.Popen(["script", "-q", "-c", "cat script.py", "/dev/null"],
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# proc = subprocess.Popen(["stdbuf", "-oL", "-eL", "cat", "script.py"],
#                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)

proc.stdout.readline()

print("printing before...")
print("printing before...")
print("printing before...")

time.sleep(2)

print("printing after...")
print("printing after...")
print("printing after...")

我得到了这种绝对奇怪的行为,以至于当子进程写入标准输出时,后续的 python 打印语句在每行之后包含几个空格,直到进程终止。这是它的截图:

在此处输入图像描述

据我所知,它在每行之后打印与终端中的列相同数量的空格。我认为这可能与回车有关,但我真的不知道。stdout我完全不明白为什么这会影响 python 的输出,因为我stderr在做Popen.

我在 Arch linux、python 版本 3.8.6 上运行它并uname -a输出:

Linux carbon 5.9.10-arch1-1 #1 SMP PREEMPT Sun, 22 Nov 2020 14:16:59 +0000 x86_64 GNU/Linux

如果我能提供任何其他信息,请告诉我。

标签: pythonpython-3.xterminalpipetty

解决方案


因为你的子进程stdin仍然是一个 TTY,script已经达到并改变了它处理 CR 和 LF 的模式。您的前 3 次打印是script在后台运行时制作的。在睡眠期间,script固定终端并退出。如果您等待子流程完成,问题就会消失......通常。信号有可能会script在其自身之后无法清理并破坏您的其余会话。可能更好的选择是重定向标准输入。

proc = subprocess.Popen(["script", "-q", "-c", "cat script.py", "/dev/null"],
    stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

这都是相当冒险的。如果执行的程序写入足够的数据来填充其标准输出管道,它将挂起。如果您只想要期望在 TTY 下运行的程序的第一行,您可以使用pty.spawn来完成这项工作。有趣的是,它的文档有一个示例script实现


推荐阅读