Résumé
Dans de nombreux cas d'utilisation, la fonction POSIXisatty()
est tout ce dont il a besoin pour détecter si stdin est connecté à un terminal. Un exemple minimal:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if (isatty(fileno(stdin)))
puts("stdin is connected to a terminal");
else
puts("stdin is NOT connected to a terminal");
return 0;
}
La section suivante compare différentes méthodes qui peuvent être utilisées si différents degrés d'interactivité doivent être testés.
Méthodes en détail
Il existe plusieurs méthodes pour détecter si un programme s'exécute de manière interactive. Le tableau suivant montre un aperçu:
cmd \ method ctermid open isatty fstat
―――――――――――――――――――――――――――――――――――――――――――――――――― ――――――――――
./test / dev / tty OK OUI S_ISCHR
./test ≺ test.cc / dev / tty OK NON S_ISREG
cat test.cc | ./test / dev / tty OK NON S_ISFIFO
echo ./test | maintenant / dev / tty FAIL NO S_ISREG
Les résultats proviennent d'un système Ubuntu Linux 11.04 utilisant le programme suivant:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main() {
char tty[L_ctermid+1] = {0};
ctermid(tty);
cout << "ID: " << tty << '\n';
int fd = ::open(tty, O_RDONLY);
if (fd < 0) perror("Could not open terminal");
else {
cout << "Opened terminal\n";
struct termios term;
int r = tcgetattr(fd, &term);
if (r < 0) perror("Could not get attributes");
else cout << "Got attributes\n";
}
if (isatty(fileno(stdin))) cout << "Is a terminal\n";
else cout << "Is not a terminal\n";
struct stat stats;
int r = fstat(fileno(stdin), &stats);
if (r < 0) perror("fstat failed");
else {
if (S_ISCHR(stats.st_mode)) cout << "S_ISCHR\n";
else if (S_ISFIFO(stats.st_mode)) cout << "S_ISFIFO\n";
else if (S_ISREG(stats.st_mode)) cout << "S_ISREG\n";
else cout << "unknown stat mode\n";
}
return 0;
}
Appareil Termimal
Si la session interactive nécessite certaines fonctionnalités, vous pouvez ouvrir le terminal et définir (temporairement) les attributs de terminal dont vous avez besoin via tcsetattr()
.
Exemple Python
Le code Python qui décide si l'interpréteur s'exécute de manière interactive utilise isatty()
. La fonctionPyRun_AnyFileExFlags()
/* Parse input from a file and execute it */
int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
if (filename == NULL)
filename = "???";
if (Py_FdIsInteractive(fp, filename)) {
int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
appels Py_FdIsInteractive()
/*
* The file descriptor fd is considered ``interactive'' if either
* a) isatty(fd) is TRUE, or
* b) the -i flag was given, and the filename associated with
* the descriptor is NULL or "<stdin>" or "???".
*/
int
Py_FdIsInteractive(FILE *fp, const char *filename)
{
if (isatty((int)fileno(fp)))
return 1;
qui appelle isatty()
.
Conclusion
Il existe différents degrés d'interactivité. Vérifier si stdin
est connecté à un tube / fichier ou à un terminal réel isatty()
est une méthode naturelle pour le faire.