我想知道如果我的输入被重定向,应该如何去执行C程序中的操作。例如,说我有我编译的程序“编”,我重定向输入“input.txt”它(我做./prog < input.txt
)。如果输入被重定向,则执行操作
如何在代码中检测到这一点?
我想知道如果我的输入被重定向,应该如何去执行C程序中的操作。例如,说我有我编译的程序“编”,我重定向输入“input.txt”它(我做./prog < input.txt
)。如果输入被重定向,则执行操作
如何在代码中检测到这一点?
一般来说,您不能判断输入是否已被重定向;但是你可以根据stdin是什么类型的文件来区分。如果没有重定向,它将是一个终端;或者它可能被设置为管道cat foo | ./prog
,或者从常规文件重定向(如您的示例),或者从多种类型的特殊文件之一重定向(./prog </dev/sda1
将其从块特殊文件重定向等) 。
所以,如果你想确定标准输入是终端(TTY),你可以使用isatty
:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
if (isatty(STDIN_FILENO))
printf("stdin is a tty\n");
else
printf("stdin is not a tty\n");
return 0;
}
如果你想其他情况下(如管道,块特殊文件,等来区分),您可以使用fstat
来提取更多的文件类型信息。请注意,这实际上并不告诉你它是否是一个终端,您仍然需要isatty
(这是一个围绕ioctl
提供有关终端信息的包装,至少在Linux上)。您可以将以下内容添加到上述程序(以及#include <sys/stat.h>
)以获取有关哪种文件标准输入是附加信息。
if (fstat(STDIN_FILENO, &sb) == 0) {
if (S_ISBLK(sb.st_mode))
printf("stdin is a block special file\n");
else if (S_ISCHR(sb.st_mode))
printf("stdin is a character special file\n");
else if (S_ISDIR(sb.st_mode))
printf("stdin is a directory\n");
else if (S_ISFIFO(sb.st_mode))
printf("stdin is a FIFO (pipe)\n");
else if (S_ISREG(sb.st_mode))
printf("stdin is a regular file\n");
else if (S_ISLNK(sb.st_mode))
printf("stdin is a symlink\n");
else if (S_ISSOCK(sb.st_mode))
printf("stdin is a socket\n");
} else {
printf("failed to stat stdin\n");
}
请注意,你将永远不会看到重定向符号链接,作为外壳将已经代表你的程序中打开文件之前取消引用的符号链接;而且我也无法让Bash打开一个Unix域套接字。但其余的都是可能的,包括令人惊讶的是,一个目录。
$ ./isatty
stdin is a tty
stdin is a character special file
$ ./isatty < ./isatty
stdin is not a tty
stdin is a regular file
$ sudo sh -c './isatty < /dev/sda'
stdin is not a tty
stdin is a block special file
$ sudo sh -c './isatty < /dev/console'
stdin is a tty
stdin is a character special file
$ cat isatty | ./isatty
stdin is not a tty
stdin is a FIFO (pipe)
$ mkfifo fifo
$ echo > fifo & # Need to do this or else opening the fifo for read will block
[1] 27931
$ ./isatty < fifo
stdin is not a tty
stdin is a FIFO (pipe)
[1]+ Done echo > fifo
$ ./isatty < .
stdin is not a tty
stdin is a directory
$ socat /dev/null UNIX-LISTEN:./unix-socket &
[1] 28044
$ ./isatty < ./unix-socket
bash: ./unix-socket: No such device or address
$ kill $!
[1]+ Exit 143 socat /dev/null UNIX-LISTEN:./unix-socket
$ ln -s isatty symlink
$ ./isatty < symlink
stdin is not a tty
stdin is a regular file
$ ln -s no-such-file broken-link
$ ./isatty < broken-link
bash: broken-link: No such file or directory