python - 为什么我必须按两次 Ctrl+D 才能关闭标准输入?

标签 python bash stdin

我有以下 Python 脚本,它读取数字并在输入不是数字时输出错误。

import fileinput
import sys
for line in (txt.strip() for txt in fileinput.input()):
    if not line.isdigit():
        sys.stderr.write("ERROR: not a number: %s\n" % line)

如果我从 stdin 获得输入,我必须按 Ctrl + D 两次 来结束程序。为什么?

当我单独运行 Python 解释器时,我只需按一次 Ctrl + D

bash $ python test.py
1
2
foo
4
5
<Ctrl+D>
ERROR: not a number: foo
<Ctrl+D>
bash $

最佳答案

在 Python 3 中,这是由于 a bug in Python's standard I/O library .该错误已在 Python 3.3 中修复。


在 Unix 终端中,键入 Ctrl+D 实际上并不会关闭进程的标准输入。但是键入 Enter 或 Ctrl+D 确实会导致 OS read 系统调用立即返回。所以:

>>> sys.stdin.read(100)
xyzzy                       (I press Enter here)
                            (I press Ctrl+D once)
'xyzzy\n'
>>>

sys.stdin.read(100) 被委托(delegate)给 sys.stdin.buffer.read,它在循环中调用系统 read() 直到它累积请求的全部数据量;或者系统 read() 返回 0 字节;或发生错误。 (docs) (source)

在第一行后按 Enter 导致系统 read() 返回 6 个字节。 sys.stdin.buffer.read 再次调用 read() 以尝试获取更多输入。然后我按下 Ctrl+D,导致 read() 返回 0 个字节。此时,sys.stdin.buffer.read 放弃并仅返回它之前收集的 6 个字节。

请注意,该进程仍然在 stdin 上有我的终端,我仍然可以输入内容。

>>> sys.stdin.read()        (note I can still type stuff to python)
xyzzy                       (I press Enter)
                            (Press Ctrl+D again)
'xyzzy\n'

好的。这是最初提出此问题时被破坏的部分。现在可以了。但在 Python 3.3 之前,存在一个错误。

这个错误有点复杂——基本上问题是两个不同的层在做同样的工作。 BufferedReader.read() 被编写为重复调用 self.raw.read() 直到它返回 0 个字节。然而,原始方法 FileIO.read() 执行了它自己的循环直到零字节。所以当你第一次在有这个错误的 Python 中按下 Ctrl+D 时,它会导致 FileIO.read() 返回 6 个字节给 BufferedReader.read(),这然后会立即再次调用 self.raw.read()。第二个 Ctrl+D 会导致 that 返回 0 字节,然后 BufferedReader.read() 最终退出。

不幸的是,这个解释比我之前的解释要长得多,但它的优点是正确。 bug 就是这样......

关于python - 为什么我必须按两次 Ctrl+D 才能关闭标准输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2162914/

相关文章:

python - 在模板中显示自定义 Django 表单错误

python - ELMo 嵌入层与 Keras

bash - awk、System() 函数、与 shell 交互

java - 从 Java 运行 PowerShell 文件显示该文件没有 '.ps1' 扩展名

java - CLI 进程的线程池

python - Scipy -- 3d griddata -- 为什么有必要将 griddata xi 参数转换为元组?

python - 是否可以过滤 Django 注释中的相关项目?

go - 从后台 go 进程读取 stdin 导致 EOF 错误

linux - shell 中的 "invalid arithmetic operator"

java - 如何从java中的命令行参数或stdin重定向读取?