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

时间:2011-09-10 02:13:12

标签: python eof tty

为了我自己的娱乐,我已经编写了一个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))

以下是你如何使用它。

$ groups | python pype.py '(l.upper() for l in sys.stdin)'
DBORNSIDE
$ 

对于预期用途,它完美无缺!

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

$ 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 D Ctrl 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'
$ 

3 个答案:

答案 0 :(得分:10)

识别

Ctrl-D 不一定是EOF,而是“终止当前read()呼叫”。

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

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

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

这一切都适用于普通的OS界面,可通过os.read()从Python访问。

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

file.readline()相反,iter(file)使用内部read()函数进行读取,因此始终具有额外 Ctrl-D 的特殊要求。 / p>

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

答案 1 :(得分:3)

Ctrl + D 被终端设备识别,终端通过生成文件结尾来响应它。也许这会有所帮助,来自维基百科(强调我的):

  

在UNIX和AmigaDOS中,键击到EOF的转换由终端驱动程序执行,因此程序不需要将终端与其他输入文件区分开来。默认情况下,驱动程序将行开头的Control-D字符转换为文件结束指示符。要在输入流中插入实际的Control-D(ASCII 04)字符,用户在其前面加上“quote”命令字符(通常是Control-V,尽管在某些系统上通过键入Control-D来实现此效果两次)。

答案 2 :(得分:0)

我不能确切地说为什么额外的CTRL + D(另一个答案在这方面做得非常好),但是这将使得输入仅在一个 CTRL + D之后打印/ kbd>,但你仍然需要 CTRL + D 第二次退出脚本

#!/usr/bin/python
DEFAULT_MODULES = ['os', 're', 'sys']

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

import sys
for x in eval(sys.argv[1], _g):
    print x,

输出:

[ root@host ~ ]$ ./test.py '(l.upper() for l in sys.stdin)'
abc
def(ENTER, CTRL+D)
ABC
DEF
qwerty(ENTER, CTRL+D)
QWERTY
[ root@host ~ ]$

编辑:

在这种情况下,

eval返回一个生成器,因此第一个EOF(CTRL + D)可能结束sys.stdin的读取,第二个停止eval生成的生成器。 / p>

Generator - 返回迭代器的函数。它看起来像一个普通函数,除了它包含yield语句,用于生成一个在for循环中可用的值,或者可以使用next()函数一次检索一个值。每个产量暂时中止处理,记住位置执行状态(包括局部变量和挂起的try-statements)。当生成器恢复时,它会在它停止的地方拾取(与每次调用时重新启动的函数形成对比)。

Generator Class reference (section 9.10)