Effectuer l’action si l’entrée est redirigée

Je veux savoir comment procéder pour exécuter une action dans un programme C si mon entrée a été redirigée. Par exemple, disons que j’ai mon programme compilé “prog” et que je lui redirige une entrée “input.txt” (je le fais ./prog < input.txt ).

Comment est-ce que je détecte ceci dans le code?

En général, vous ne pouvez pas savoir si une entrée a été redirigée. mais vous pouvez distinguer en fonction du type de fichier stdin. S’il n’y a pas eu de redirection, ce sera un terminal; ou il aurait pu être mis en place comme un cat foo | ./prog pipe cat foo | ./prog cat foo | ./prog , ou une redirection à partir d’un fichier normal (comme dans votre exemple), ou une redirection à partir de plusieurs types de fichiers spéciaux ( ./prog redirigeant depuis un fichier spécial de bloc, etc.).

Donc, si vous voulez déterminer si stdin est un terminal (TTY), vous pouvez utiliser isatty :

 #include  #include  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; } 

Si vous souhaitez faire la distinction entre d'autres cas (comme un canal, un fichier spécial de bloc, etc.), vous pouvez utiliser fstat pour extraire des informations supplémentaires sur le type de fichier. Notez que cela ne vous dit pas réellement s'il s'agit d'un terminal, vous avez toujours besoin de isatty pour ce faire, il s'agit d'un wrapper autour d'un ioctl qui récupère des informations sur un terminal, du moins sur Linux). Vous pouvez append les éléments suivants au programme ci-dessus (avec #include ) pour obtenir des informations supplémentaires sur le type de fichier stdin.

 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"); } 

Notez que vous ne verrez jamais un lien symbolique à partir d'une redirection, car le shell aura déjà déréférencé le lien symbolique avant d'ouvrir le fichier au nom de votre programme; et je ne pouvais pas obtenir Bash pour ouvrir un socket de domaine Unix non plus. Mais tout le rest est possible, y compris, de manière surprenante, un répertoire.

 $ ./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