我想知道如果我的輸入被重定向,應該如何去執行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