为什么我要两次输入ctrl-d?

Sin*_*ion 16 python tty eof

为了我自己的娱乐,我已经编写了一个python脚本,允许我使用python进行bash one-liners; 提供python生成器表达式; 并且脚本遍历它.这是脚本:

DEFAULT_MODULES = ['os', 're', 'sys']

_g = {}
for m in DEFAULT_MODULES:
    _g[m] = __import__(m)

import sys
sys.stdout.writelines(eval(sys.argv[1], _g))
Run Code Online (Sandbox Code Playgroud)

这就是你如何使用它.

$ groups | python pype.py '(l.upper() for l in sys.stdin)'
DBORNSIDE
$ 
Run Code Online (Sandbox Code Playgroud)

对于预期用途,它完美地工作!

但是当我不用管道输入它并直接调用它时,例如:[强调添加以显示我键入的内容]

$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooEnter
barEnter
bazEnter
Ctrl DCtrl D'foo\n'
'bar\n'
'baz\n'
$ 

为了停止接受输入并产生任何输出,我必须要么键入Enter- Ctrl D- Ctrl DCtrl D- - .Ctrl D Ctrl D这违反了我的期望,每行应按输入处理,并且Ctrl D随时打字将结束脚本.我理解的差距在哪里?

编辑:我已经更新了交互式示例,以表明我没有看到他在答案中描述的引用wim,以及更多的例子.

$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooCtrl DCtrl DbarEnter
Ctrl DCtrl D'foobar\n'
$ python pype.py '("%r\n" % (l,) for l in sys.stdin)'
fooCtrl VCtrl D^DbarEnter
Ctrl DCtrl D'foo\x04bar\n'
$ 

glg*_*lgl 10

Ctrl-D被识别的不一定是EOF,而是"终止当前read()通话".

如果您有一个空行(或只是按下Ctrl-D)并按Ctrl-D,则read()立即终止并返回0个读取字节.这是EOF的标志.

如果您有一行中的数据并按下Ctrl-D,则会read()终止所有已键入的内容,当然没有终止换行符('\n').

因此,如果您有输入数据,则按Ctrl-D两次非空行,或者按空一行,即使用Enter之前.

这一切都适用于普通的OS接口,可以通过Python访问os.read().

Python文件对象以及文件迭代器将第一个EOF视为当前read()调用的终止,因为它们认为不再存在任何内容.下一次read()调用再次尝试,需要另一个Ctrl-D才能真正返回0个字节.原因是文件对象read()总是尝试返回所请求的字节数,并在OS read()返回少于请求时尝试填充.

与之相反file.readline(),iter(file)使用内部read()函数进行读取,因而总是有额外的这种特殊要求Ctrl-D.

我总是用来iter(file.readline, '')从文件中逐行读取.