Mic*_*fik 13 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)
Run Code Online (Sandbox Code Playgroud)
如果我从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 $
Run Code Online (Sandbox Code Playgroud)
Jas*_*rff 14
在Python 3中,这是由于Python的标准I/O库中的一个错误.该错误已在Python 3.3中修复.
在Unix终端中,键入Ctrl + D实际上并不关闭进程的stdin.但是输入Enter或Ctrl + D会导致OS read
系统调用立即返回.所以:
>>> sys.stdin.read(100)
xyzzy (I press Enter here)
(I press Ctrl+D once)
'xyzzy\n'
>>>
Run Code Online (Sandbox Code Playgroud)
sys.stdin.read(100)
委托给sys.stdin.buffer.read
,在循环中调用系统read(),直到它累积完整请求的数据量; 或者系统read()返回0个字节; 或者发生错误.(docs) (来源)
在第一行后按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'
Run Code Online (Sandbox Code Playgroud)
好.当这个问题最初被问到时,这是被破坏的部分.它现在有效.但在Python 3.3之前,存在一个错误.
这个bug有点复杂 - 基本上问题是两个独立的层正在做同样的工作.BufferedReader.read()
被写入self.raw.read()
反复调用,直到它返回0字节.但是,raw方法FileIO.read()
执行了自己的循环 - 直到零字节.因此,第一次在Python中按Ctrl + D时会出现此错误,这将导致FileIO.read()
返回6个字节BufferedReader.read()
,然后立即self.raw.read()
再次调用.第二按Ctrl + d会导致该返回0字节,然后BufferedReader.read()
将最终退出.
不幸的是,这种解释比我之前的解释长得多,但它具有正确的优点.虫子就像那样......
我在这个问题的回答中写了对此的解释。
简而言之,终端上的 Control-D 只是导致终端刷新输入。这使得read
系统调用返回。第一次它返回一个非零值(如果您输入了某些内容)。第二次,它返回 0,这是“文件结束”的代码。