为什么 Ctrl-D (EOF) 退出 shell?

Gee*_*eeb 89 shell escape-characters

您是否真的通过输入此转义序列来“结束文件”,即交互式 shell 会话是否被 shell 视为真正的文件流,就像任何其他文件流一样?如果是,是哪个文件?

或者,Ctrl+D信号只是一个占位符,表示“用户已完成输入,您可以终止”?

Sté*_*las 99

^D字符(也称为\04或为0x4,传输结束以Unicode)是默认值eof在内核中终端或伪终端驱动器的专用控制字符参数(更精确地的tty连接到串行或伪线路规程tty 设备)。这是传递给 TCSETS/TCGETSc_cc[VEOF]termios结构的ioctl一个问题,它会影响终端设备的驱动程序行为。

发送这些的典型命令ioctlsstty命令。

要检索所有参数:

$ stty -a
速度 38400 波特;第 58 行;第 191 栏;线 = 0;
内部= ^ C; 退出 = ^\; 擦除 = ^?; 杀 = ^U; eof = ^ D ; eol = <undef>; eol2 = <undef>; swtch = <undef>; 开始 = ^Q; 停止 = ^ S; 暂停 = ^ Z; rpnt = ^R; wase = ^W; lnext = ^V; 冲洗 = ^O;
分钟 = 1; 时间 = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

eof参数仅在终端设备处于icanon模式时相关。

在这种模式下,终端驱动程序(不是终端仿真器)实现了一个非常简单的行编辑器,您可以在其中键入Backspace以擦除字符,Ctrl-U擦除整行......当应用程序从终端设备读取时,它什么也看不到,直到您按下Return该点read()返回包括最后一个LF字符的整行(默认情况下,终端驱动程序还将CR您的终端发送的转换ReturnLF)。

现在,如果您想在不按 的情况下发送到目前为止Enter输入的内容,您可以在此处输入eof字符。从终端仿真器接收到该字符后,终端驱动程序提交该行的当前内容,以便执行该操作的应用程序read将按原样接收它(并且不会包含尾随LF字符)。

现在,如果当前行为空,并且应用程序将完全读取先前输入的行,read则将返回 0 字符。

这表示应用程序的文件结束(当您从文件中读取时,您一直在读取,直到没有其他可读取的内容为止)。这就是为什么它被称为eof字符,因为发送它会导致应用程序看到没有更多的输入可用。

现在,现代 shell 在提示符下不会将终端设置为icanon模式,因为它们实现了自己的行编辑器,这比内置的终端驱动程序要先进得多。然而,在他们自己的行编辑器中,为了避免混淆用户,他们赋予^D字符(或终端的任何eof设置)相同的含义(表示eof)。


Tho*_*erk 11

CTRL_D 只是一个信号,表明这是文本流的结尾。您不是用它结束文件,而是通过键入它来结束您的输入流。此外 CTRL_D 不代表任何字符或字节,您可以使用工具 hexdump 找到:

# cat >test.txt
asdf# hexdump -C test.txt 
00000000  61 73 64 66                                       |asdf|
00000004
# ll test.txt 
-rw-r--r-- 1 root root 4 Jan 21 11:55 test.txt
Run Code Online (Sandbox Code Playgroud)

  • 它结束 shell 的原因是 shell 基本上是一个接受输入并处理输入的进程。当你告诉它不再有输入时,shell 就没有什么可做的了。 (5认同)
  • 是的,进入 bash 的流和其他流一样是输入流。CTRL_D 表示输入流已结束,bash 可以退出。 (2认同)