2014-11-05 68 views
3

我想知道如果我的輸入被重定向,應該如何去執行C程序中的操作。例如,說我有我編譯的程序「編」,我重定向輸入「input.txt」它(我做./prog < input.txt)。如果輸入被重定向,則執行操作

如何在代碼中檢測到這一點?

回答

6

一般來說,您不能判斷輸入是否已被重定向;但是你可以根據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 
相關問題