如果一个程序读写同一个缓冲区会发生什么?

What happend if a program read and write to same buffer?

我遇到的是我写了一个示例 python 脚本,名为 tt.py:

import time

while True:
    print(123)
    time.sleep(0.5)

我运行它被python tt.py &,它会输出到终端123 on-going。如果我在输入 s 几秒钟后输入字符 l,命令 ls 工作正常。

但是为什么,我知道一点伪终端:主端和从端。我认为 bash 的 stdin、stdout、stderr 是重定向到从端。所以在我看来,bash 应该 return 命令像 l123\n123\n...s 没有找到。

所以更普遍的问题是 bash 如何知道当它们指向相同的文件描述符时哪个是输出哪个是输入?

或者我在这种情况下哪里理解有误,在此先感谢!


更新:

我知道 stdin 和 stdout 指向不同的描述符,但它们可以指向相同的描述符吗?

所以在我看来,python 脚本的标准输出到伪终端的从端,而终端在主端显示流。似乎我无法弄清楚终端标准输入是如何转到 bash 的标准输入的。不是先去master端再去slave端再bash吗?

如果是这样,我认为在主控方会搞砸,因为它同时接收 python 脚本的输出和终端的输入。

您误解了 POSIX standard streams 的工作原理。有 单独的流 用于输入(stdin),以及用于正常和错误输出(stdoutstderr)。这些不是唯一可能的流。

当您将一个进程置于后台(使用 &)时,该进程将继承与 bash 相同的标准流。所以 Python 进程 stdout 与 bash stdout 是同一个流。然而,Bash 不是从标准输出 读取。您的 PTY(终端)只是显示写入标准输出流的所有数据。

要明确说明:bash 从未收到 Python 写入标准输出的数据,在其 stdin 上。您在键盘上输入的字符被发送到 bash 进程 stdin 流,与 Python 进程正在生成的输出完全分离。

注意,从bash和Python的角度来看,它们只是连接到标准流(它们可以test if the stream is connected to a terminal),流与否无关紧要连接到真实终端或伪终端。伪终端是 而不是 将 Python 输出发送回 bash ;它的行为就像任何终端一样;从连接的程序接收到的数据 被视为键盘输入。 PTY 的主从端都知道如何处理输入和输出并将它们分开:

一般来说,您会在屏幕上看到 ls 回显,因为 PTY 设置为 回显输入(bash 不会将其写回收到输入后)。

一个伪终端由两个独立的数据通道组成,每个通道都有自己的缓冲区。

有一个通道可以将写入从属 pty 的数据传输到主 pty。还有一个通道将写入主 pty 的数据传输到从 pty。

任何写入 pty 从属端的内容都由连接到主控端的进程读取。在这种情况下,它是您的终端应用程序。它在终端 window.

中显示此数据

pythonls 都在写入从属 pty,它们的输出显示在 window。

当应用程序从从属 pty 读取时,它会获取其他进程写入主控端的内容。终端应用程序写入您在键盘上键入的内容,而不是发送到从属端的输出。

因此 python 脚本的输出不会被 shell 读取为输入。

如果这两个方向不是独立的,那么每个产生输出并读取输入的程序都会完全混淆,因为它最终会读取自己的输出。

So in my mind, the bash should return command like l123\n123\n...s not found.

bash 在交互模式下运行在其 stdin 上提供的命令(例如,键盘输入)。子进程(在本例中为 python)写入它从 bash 继承的 stdout(例如,显示)。默认情况下,stdout 数据不会进入 stdin(尽管 )。

在这种情况下,python 是否是 bash 的 background/foreground 工作并不重要(它不会改变 python 的输出去向和我们不关心 stty tostop here) or whether a pseudoterminal is used or you're looking at the console directly. bash may use fork, exec syscalls to start child processes & dup2 to configure their stdin/stdout/stderr streams e.g, a pipeline implemented via recursive calls -- 单个命令没有重定向。