我有以下两个测试文件:
test1 test2
两者都是空白。现在我发出以下命令:
$ cat > test1
Enter
This is a test file
Enter
Ctrl+D
$ cat > test2
Enter
This is another test file
Enter
^C
Ctrl+C
$
现在我检查两个文件的内容
$ cat test1
This is a test file
$ cat test2
This is another test file
$
那么,如果我们使用上述两种方法来达到相同的结果,结果有什么真正的区别吗?
答案1
当cat
命令运行时,终端处于规范输入模式。简而言之,这意味着终端的线路纪律正在处理行编辑,并响应所有特殊字符为终端配置(可通过命令查看和设置stty
)。
该cat
命令只是read()
从其标准输入中进行 ing,直到read()
调用返回读取的零字节(这是命中文件末尾的 POSIX 约定)。
终端并没有真正的“终点”。但存在read()
终端设备返回零字节的情况。当线路规则收到“EOF”特殊字符时,无论当时配置了什么,它都会导致read()
返回当时编辑缓冲区中的任何内容。如果编辑缓冲区为空,则返回从 读取的零字节read()
,导致cat
退出。
cat
也退出以响应其默认操作是终止进程的信号。线路规则还生成响应特殊字符的信号。 “INTR”和“QUIT”特殊字符导致INT
和QUIT
信号被发送到前台进程(组),该进程将是/包含该cat
进程。这些信号的默认操作是终止进程cat
。
这导致了可观察到的差异:
- Ctrl+D仅当它是 EOT 特殊字符时才有此动作。这是通常情况如此,但事实并非如此一定案子。同样,Ctrl+C只有当它是INTR特殊字符时才起作用。
- Ctrl当该行当时实际上不为空时,+D不会导致终止。不过, +会
cat
产生中断。CtrlC cat
如果发现缓冲区标准输出指向文件,则 C 语言中的简单实现将阻止缓冲区标准输出,如问题中所示。理论上,如果cat
由 终止,这可能会导致缓冲但尚未输出的行丢失SIGINT
。实际上,BSD 和 GNU C 库实现了 C 或 C++ 语言标准中未描述的缓冲模式。重定向到文件或管道时的标准输出是智能缓冲。它是块缓冲的;除了每当 C 库发现自己即将
read()
从向终端设备打开的任何文件描述符开始新行时,它都会刷新标准输出。 (严格来说,BSD 和 GNU C 库并不完全实现相同的语义,而且做的事情还不止于此,但这种行为是一个常见的子集。)因此,当中断信号cat
构建在这样的之上时,不会导致丢失缓冲输出。C 库。- 当然,如果
cat
是命令管道的一部分,有些其他cat
在这些数据到达输出文件之前,进程可以在下游缓冲数据。因此,当线路规则发送SIGINT
(默认情况下)终止管道中的所有进程时,缓冲且尚未写入的输入数据将丢失;而cat
使用“EOF”特殊字符正常终止将导致管道正常终止,所有数据之前都会传递到下游进程它收到 EOF 指示它是read()
其标准输入。
请注意,这与交互式 shell 读取您的一行输入时发生的情况关系不大。当你的 shell 等待输入时,终端处于非规范输入模式,在哪种模式下线路纪律不做对特殊字符的任何特殊处理。 shell 如何处理Ctrl+D和Ctrl+C完全取决于 shell 使用的输入编辑库(libedit、readline 或 ZLE)以及该编辑库的配置方式(使用键绑定等)。
进一步阅读
- POSIX 终端接口。维基百科。
答案2
CTRL+C 是中断信号。它将停止该命令。
CTRL+D是文件结尾或exit()
.当您输入CTRL+时D,它因文件结尾而退出命令。如果你在 shell 中输入CTRL+ ,什么也不会发生。C但是,如果您输入CTRl+ D,它将从大多数系统中当前的 Shell 中退出。