如果提供文件名,我的程序从文件中读取,否则从
stdin
读取:
if (isatty(STDIN_FILENO)) {
if ( !(f = fopen(argv[1], "r")) )
{
perror(argv[1]);
return 1;
}
}
else
f = stdin;
while ((size = getline(&line, &len, f)) != -1) {
...
这是正确的错误处理吗? 我是否需要对
stdin
进行错误处理,或者是否没有打开失败的情况?
顺便说一句,我有点困惑,
isatty(STDIN_FILENO)
在字面上“是NOT一个TTY”的地方返回真。
我本以为我的 if 检查会反向工作。
你只需要
FILE *f;
if ( argc < 2 || strcmp( argv[1], "-" ) == 0 ) {
f = stdin;
} else {
f = fopen( argv[1], "r" );
if ( !f ) {
perror(argv[1]);
exit( 1 );
}
}
解释如下。
你把事情复杂化了。您只需要查看参数即可。
./prog
应该从stdin
../prog -
应该从stdin
读。 (可选)./prog file
应该从文件中读取file
.如果是这样,
./prog file
按预期工作。./prog <file
按预期工作。cat file | ./prog
按预期工作。这是一个常见的范例。
$ echo 'From file' >file
$ echo 'From stdin' | cat
From stdin
$ echo 'From stdin' | cat -
From stdin
$ echo 'From stdin' | cat file
From file
$ echo 'From stdin' | grep ''
From stdin
$ echo 'From stdin' | grep '' -
From stdin
$ echo 'From stdin' | grep '' file
From file
$ echo 'From stdin' | perl -pe1
From stdin
$ echo 'From stdin' | perl -pe1 -
From stdin
$ echo 'From stdin' | perl -pe1 file
From file
$ echo 'echo "From file"' >file
$ echo 'echo "From stdin"' | sh
From stdin
$ echo 'echo "From stdin"' | sh -
From stdin
$ echo 'echo "From stdin"' | sh file
From file
根据它是否是终端来决定是否从 stdin 读取可能会导致问题。 stdin 不是终端是很常见的。例如,守护进程的标准输入没有连接到终端,因此由守护进程启动的程序的标准输入不是终端(除非守护进程采取措施使其成为终端)。
isatty
只应在此处使用,如果你想拒绝从终端读取。我见过一两个程序这样做,但这种情况极为罕见。
我有点困惑 isatty(STDIN_FILENO) 在字面上“不是 TTY”的地方返回 true。
你确实糊涂了。它恰恰相反。 “如果 fd 是指向终端的打开文件描述符,则 isatty() 返回 1;否则返回 0,并设置 errno 以指示错误。”
如果提供文件名,我的程序从文件中读取,否则从
读取stdin
您应该只测试是否提供了文件名并使用
fopen()
打开文件或将 stdin
分配给 FILE *f
否则。
读完
f
后,您还可以比较f == stdin
来决定是关闭文件还是保持stdin
打开。
isatty()
用于测试标准输入是否连接到终端,STDIN_FILENO
是标准输入的系统句柄,0
在 unix 系统上。这个函数不是 C 标准的一部分,而是在 POSIX 标准中定义的。
isatty(fd)
如果系统句柄 fd
指的是终端,则返回非零。如果 0
无效(并且 fd
设置为 errno
),并且如果 EBADF
不指代终端,则将 fd
设置为 errno
或 EINVAL
(由 POSIX.1-2001 规定)。按照编码,程序测试标准输入是否已从文件或管道重定向,在这种情况下它从 ENOTTY
读取,否则(如果
stdin
附加到终端)它尝试打开文件名。 stdin
当然会失败,如果没有提供文件名,将空指针传递给 fopen
实际上会导致未定义的行为。只是测试是否提供了文件名似乎更合适。如果没有提供文件名或者文件名是fopen
,在许多unix工具中习惯从
stdin
读取,所以你可能也想支持这个约定。还要注意,"-"
接受一个指向缓冲区分配大小的指针,并返回从流中读取的行的长度。因此,转置变量名称似乎更一致。
getline