我刚刚学会了使用命令创建新文件的技巧cat
。根据我的测试,如果最后一行后面没有换行符,我必须输入ctrl+d两次才能完成输入,如下所示。
[root@192 ~]# cat > 测试 A 乙 ctrl+d[root@192 ~]# cat > 测试 A b ctrl+dctrl+d[root@192 ~]#
这是预期的吗?为什么会有这种行为?
答案1
是的,这是预期的。
我们说 Ctrl-D 可以cat
在输入中看到“文件结尾”,然后停止读取并退出,但事实并非如此。由于这是在终端上,所以没有实际的“结束”,事实上它并不是真正的“文件结束”曾经检测到,但任何read()
零字节。
通常,read()
系统调用不会返回零字节,除非知道没有更多可用字节,例如在文件末尾。当从没有可用数据的网络套接字读取时,预计新数据将在某个时刻到达,因此系统调用将阻塞并等待某些数据到达,而不是零字节读取,或者返回错误说它会阻止。如果连接被关闭,那么它将返回零字节。话又说回来,即使在文件上,在末尾(或过去)读取也不是无休止的最终结束,因为另一个进程可以向文件写入一些内容以使其更长,之后新的读取尝试将返回更多数据。 (这就是 的简单实现所tail -f
要做的。)
对于许多用例来说,将“零字节读取”视为“检测到文件末尾”恰好工作得足够好,以至于在实践中它们被认为是实际上相同的事情。
Ctrl-D 在这里的作用是告诉终端驱动程序传递到目前为止所给出的所有内容,即使它还不是完整的行。在一行的开头,全部是零字节,被检测为 EOF。但在字母 后b
,第一个 Ctrl-D 发送b
,然后下一个发送在 后输入的零字节b
,现在被检测为 EOF。
您还可以看到如果您在cat
没有重定向的情况下运行会发生什么。它看起来像这样,斜体部分是我输入的内容:
$猫 富Ctrl-D富
当按下 Ctrl-D 时,cat
获取输入foo
,将其打印回来并继续等待输入。该行看起来像foofoo
,之后没有换行符,因此光标停留在末尾。
答案2
简单说几句。
据我所知,快速浏览一下源代码,cat
使用缓冲区来优化其工作流程。参考cat
来自标准输入且没有特殊命令行选项的简单调用的行为:
- 当缓冲区为空时,单个Ctrl+D就足以退出;
- 如果不是,则第一个 Ctrl-D 强制缓冲区倾倒(变成空),第二个被解释为退出命令。
这意味着,如果您运行cat> test
并简单地输入, Ctrl-D 您将在当前目录中创建一个空文件(名为test
),或者如果该文件已存在,您将清空该文件,而不需要第二个 Ctrl-D 。
超出了这个问题的范围,但不是那么遥远:应该注意的是,如果您将字符发送到终端/shell 实例,不必要的第二秒Ctrl-D可能会导致不必要的退出(主要与上面的示例有关)。