我推翻了 中的陈述if/else
,现在更正。
我正在阅读以下代码片段UNIX® 环境中的高级编程:
该程序测试其标准输入,看看它是否能够进行查找。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void){
if(lseek(STDIN_FILENO,0, SEEK_CUR) == -1)
printf("cannot seek\n");
else{
printf("seek ok\n");
}
}
我编译并运行它(在 下Ubuntu 18.04.2 LTS
)但不理解以下行为。
//1
$ ./a.out
cannot seek
//2
$ ./a.out < /etc/passwd
seek OK
//3
$ cat < /etc/passwd | ./a.out
cannot seek
//4
$ ./a.out < /var/spool/cron/FIFO
cannot seek
为什么//1
是cannot seek
?我想空stdin
应该可以求到。是因为stdin
还没开封吗?因为我听说通常stdin
和stdout
是stderr
在程序开始运行时打开的。
为什么//2
可以,为什么//3
不行?我认为它们是一样的。
答案1
//1 ./a.out
:
如果您不重定向 stdin (无管道和 no <
),则 stdin 将从父进程继承。当您a.out
在 shell 中以交互方式运行时,它会继承将键盘输入作为 stdin 获取的终端设备。
终端设备通常不可查找,因为它们代表用户交互,但根据 POSIX 标准,lseek
可能会返回成功并且不执行任何操作。在 Linux 上lseek
失败并显示ESPIPE
.
//2 ./a.out < /etc/passwd
:
这里 stdin 被重定向到一个打开的文件。正如/etc/passwd
常规文件一样,它是可查找的。
//3 cat < /etc/passwd | ./a.out
:
在这里,您启动两个进程(cat
和./a.out
)并用管道连接它们。
cat
(没有其他参数)读取它的 stdin ( /etc/passwd
) 并将其复制到它的 stdout (连接到 的管道./a.out
)。这与 的情况不同//2
。从标准输入的角度来看,./a.out
无法进行查找,因为它只是连接到另一个进程的管道。
//4 ./a.out < /var/spool/cron/FIFO
:
在这里你有一个命名管道或类似的特殊文件。本案与此类似//3
。您与另一个进程有单向连接。而这些都是不可寻找的。