我的程序可以调用哪些代码来实现与在终端中按Ctrl+类似的行为?D也就是说,要使read
在 STDIN 上调用的函数在子进程中返回0
,但不会在父进程中关闭此“STDIN”文件描述符?
我试图了解 EOF 条件如何传达给 Linux 中的进程。
看来read
返回0
只是建议性的,遇到这样的EOF情况后实际上可以继续阅读。考虑以下程序:
#include <unistd.h>
#include <stdio.h>
void terminate_buf(char *buf, ssize_t len)
{
if(len > 0) {
buf[len-1] = '\0';
} else {
buf[0] = '\0';
}
}
int main()
{
int r;
char buf[1024];
while(1) {
r = read(0, buf, 1024);
terminate_buf(buf, r);
printf("read %d bytes: %s\n", r, buf);
}
return 0;
}
如果您编译(gcc -o reader reader.c
假设您将其命名为 reader.c)并在终端中运行该程序,然后按Ctrl+ D,然后输入foobar
Enter,您将看到以下内容:
$ ./reader
read 0 bytes:
foobar
read 7 bytes: foobar
表明在 EOF 事件发生后完全有可能读取有意义的数据。您可以在一行上多次按Ctrl+ ,然后按一些文本,然后继续读取数据,就好像什么也没发生一样(在每次按+打印“read 0 bytes: ”之后)。文件描述符保持打开状态。Dreader
CtrlD
那么这里发生了什么以及我如何复制这种行为?如何使子进程在看到 EOF 后看到一些数据?有没有办法只使用常规文件 I/O(也许还有ioctl
s)来做到这一点,或者我需要打开一个 pty?计数为 0 的调用write
似乎不起作用,read
甚至在另一端也没有返回。什么是EOF,真的吗?
答案1
Ctrl-D (0x04) 由终端设备映射到 EOF。如果您从管道或文件中读取数据,则不会发生这种情况。
echo -e "a\x04b" | cat
或者
echo -e "a\x04b" | hd
例如,如果管道中的第一个程序正在从终端读取数据,并且您想忽略映射的 EOF,则可以更改终端行为:
stty eof -
并且 Ctrl-D 将不再起作用。或者您可以通过以下方式更改整个生产线规则:
stty raw
并像读取文件一样读取它,无需转换。
您可以使用 EOF 字符发送多个文件,前提是这些文件都不包含该字符。一个 pty 就可以做到。
但是,您可能会更好地使用已建立的解决方案,例如 MIME multipart、zmodem 或归档到管道(例如,这里第二个tar
列出了第一个归档的文件:)tar cf - *txt | tar tf -
。
答案2
问题是,确实不存在“EOF 条件”这样的东西。按照惯例,返回 0 的读取被解释为文件末尾,但正如您所看到的,您可以继续读取。额外的读取可能会再次返回 0,或者如果其他进程同时写入该文件,则它们可以返回更多数据。
甚至Ctrl-D
来自终端的信号也不具有特殊的“EOF”信令属性。它真正做的是将当前行输入返回到进程,就像按 Enter 键一样,但区别在于不附加换行符。如果按 Ctrl-D 作为一行(即空行)上的第一个输入,则返回零个字符,这再次按照惯例被解释为“EOF”。
如何解释 read 的返回值 0 由调用 read 系统调用的进程决定。