如何发出输入结束信号以“读取-N”?

Kus*_*nda 6 bash ksh tty user-input read

我一直试图弄清楚如果我Ctrl+D使用read -N 1inbashksh93.

我知道传输结束字符和文件结束条件之间的区别,并且我知道Ctrl+D在使用readwithout时会做什么-N(它发送 EOT,如果输入为空,则底层read()返回零,发出信号EOF)。

但我不确定为什么尝试读取特定数量的字符会如此彻底地改变这种行为。我会期望 EOF 条件并且以下循环将退出:

while read -N 1 ch; do
  printf '%s' "$ch" | od
done
Run Code Online (Sandbox Code Playgroud)

按下时输出Ctrl+D

0000000   000004
0000001

bash手册说,关于read -Nksh93也有类似的措辞):

-N nchars; read 在完全读取nchars字符后返回,而不是等待完整的输入行,除非遇到 EOF或读取超时。

...但它没有说明将 TTY 切换到原始/无缓冲模式(这是我假设正在发生的情况)。

-n选项read似乎在关于以同样的方式工作Ctrl+D,并且要读取的字符数目似乎没有任何关系。

我如何read -N向循环发出结束输入信号并退出循环(除了测试读取的值),为什么这与“裸”不同read

jth*_*ill 6

如果文档指出没有 ASCII EOF 这样的东西,^D 的 ASCII 语义是 EOT,这是终端驱动程序在规范模式下提供的:它结束当前传输,read. 程序0 长度读取解释为 EOF,因为这就是具有 EOF 的文件的样子,但是终端驱动程序拒绝提供字符代码 4 而是吞下它并终止读取并不总是您想要的。

这就是这里发生的事情:控制字符语义是规范模式的一部分,终端驱动程序在该模式下进行缓冲,直到它看到约定赋予特殊含义的字符。EOT、BS、CR 和许多其他人都是如此(请参阅stty -aman termios了解所有血腥细节)。

read -N是仅传递接下来的 N 个字符的显式命令。为此,shell 必须停止向终端驱动程序询问规范语义。

顺便说一下,EOF 实际上并不是终端可以设置或输入的条件。

如果您继续阅读其他任何内容的 eof,您将继续获得 EOF 指示符,但终端驱动程序可以提供的唯一 EOF 是一个伪造的 EOF——想想看——如果终端驱动程序实际上提供了一个真正的 EOF,那么 shell之后也无法继续阅读。都是同一个终端。这里:

#include <unistd.h>
#include <stdio.h>
char s[32];
int main(int c, char**v)
{
    do {
        c=read(0,s,sizeof s);
        printf("%d,%.*s\n",c,c,s);
    } while (c>=0);
}
Run Code Online (Sandbox Code Playgroud)

在终端上尝试一下,您会看到规范模式下的终端驱动程序只是解释 EOT 以完成任何未完成的读取,并且它会在内部进行缓冲,直到它看到一些规范的输入终止符,而不管读取缓冲区的大小(键入长于 32 的行字节)。

令你困惑的文字¸

除非遇到EOF

指的是真正的EOF。

  • 这是一个很长的漫谈,并没有回答 OP 的问题:为什么 EOT 在没有 `-N` 的情况下在 `read` 中充当 EOF,而不是在 `read -N` 中充当 EOT? (3认同)