【问题标题】:Last line of stdin not being read when EOF is detected检测到 EOF 时未读取最后一行标准输入
【发布时间】:2016-02-05 03:25:27
【问题描述】:

可能是一个简单的问题,但我基本上是在尝试复制 cat 命令的行为(非常稀疏和简单),但在 python 中。我希望用户能够输入他们想要的所有文本,然后当他们输入 EOF(通过按 ctrl+dcmd+d)时,程序应该打印出他们输入的所有内容。

import sys
for line in sys.stdin:
    print line

如果我输入输入行并在最后一行后面加上回车符,然后按cmd+d

never gonna give you up
never gonna let you down
never gonna run around
and desert you

那么输出就是

never gonna give you up
never gonna let you down
never gonna run around
and desert you

但是,如果我还在最后一行“and desert you”上按cmd+d,则输出为:

never gonna give you up
never gonna let you down
never gonna run around

如何修改程序,如果用户在最后一行按下 EOF,那么它仍应包含在输出中?

【问题讨论】:

  • 它的环境特定...你在哪个操作系统上?
  • 您或许应该阅读一下No final newline。当然,它讨论的是 shell 脚本而不是 Python,但其中一些问题是相似的,并且来自同一来源;该代码显示最后一行,并且不显示最后一行之后的尾随数据。

标签: python stdin


【解决方案1】:

Control-D 的行为实际上是操作系统的 TTY 驱动程序的功能,而不是 Python 的功能。 TTY 驱动程序通常一次向程序发送一整行数据。您会注意到“cat”和大多数其他程序的行为方式相同。

按照您的要求去做并非易事。它通常需要将 TTY 置于原始模式,读取和处理数据(您将获得 Control-D 字符本身),然后在退出之前将其退出原始模式(您不想以原始模式退出!)

执行此操作的过程取决于操作系统,但您也许可以使用 tty.setraw() 和 tty.setcbreak()。

【讨论】:

    【解决方案2】:

    好吧,这很奇怪,但事实证明是有解释的。 ctrl-d 是“传输结束”(EOT),而不是 EOF。它的含义是特定于环境的,但对于 *nix 终端来说,它意味着立即将输入缓冲区刷新到程序中。

    如果缓冲区中有字符,python 的标准输入会获取它们,但由于没有 \n,标准输入迭代器会缓冲它们并且不会发出任何内容。

    如果缓冲区中没有字符,python的标准输入会得到一个空缓冲区,python遵循空缓冲区意味着EOF的规则,它应该停止迭代。

    如果您键入一些字符,然后连续输入 2 个 ctrl-d,您将获得缓冲的字符并且迭代将结束。而且,为了让事情尽可能复杂,如果您启动另一个 for line in sys.stdin,它会很乐意继续接受输入。

    编辑

    当您使用输入缓冲区中的数据按 ctrl-d 时,此脚本将立即为您提供任何待处理字符,但除非您按第二个 ctrl-d,否则它不会知道退出

    import sys
    
    while True:
        c = sys.stdin.read(1)
        if not c:
            break
        sys.stdout.write(c)
        sys.stdout.flush()
    

    【讨论】:

    • 如果我从 lubuntu 中的 *nix 操作系统运行它,我还会遇到这个问题吗?我在安装 vbox 时在 OS X 中编码,那时我注意到了这个问题。我现在设置了一个 lubuntu 虚拟机,我只需要让这段代码在这个环境下工作
    • 我在 linux mint(基于 ubuntu)上,我用 python 3.5 复制了你的问题,所以是的,我认为它仍然是一个问题。 @Curt 有一个有趣的建议,但您也许可以做一些事情,比如一次读取 1 个字符来绕过它。
    • 我不认为你真的能得到你想要的行为——“如果用户在最后一行按下 EOF”——因为 EOT 被终端吞下了驱动程序,它所做的只是刷新输入缓冲区。 read(1) 将在按下 ctrl-d 时为您提供所有字符,但您不知道退出。用户必须再次按下它。
    • 我很欣赏编辑,但有没有办法可以设置它,以便用户可以输入一个文本块,然后打印出该块,而不是这个打印出每一行的解决方案进入?这是一个很好的解决方案,我更喜欢前者
    【解决方案3】:

    我认为这是 python 2.7 的问题。我在 Python 3.5 上尝试了你的代码,它工作得很好。

    希望这会有所帮助!

    【讨论】:

    • 我在 python 2.7 中尝试过它只是挂起,但在 python 3.5 中它表现出 OP 提到的奇怪行为。你在哪个操作系统上?我是linux。
    • 我在 Windows 10 上,使用 Anaconda Python 3.5
    猜你喜欢
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 2018-09-24
    相关资源
    最近更新 更多