Detecta si stdin es un terminal o una tubería?

Cuando ejecuto ” python ” desde el terminal sin argumentos, aparece el shell interactivo de Python.

Cuando ejecuto ” cat | python ” desde el terminal, no se inicia el modo interactivo. De alguna manera, sin obtener ninguna entrada, ha detectado que está conectado a una tubería.

¿Cómo haría una detección similar en C o C ++ o Qt?

Use isatty :

 #include  #include  ... if (isatty(fileno(stdin))) printf( "stdin is a terminal\n" ); else printf( "stdin is a file or a pipe\n"); 

(En ventanas están precedidos por guiones bajos: _isatty , _fileno )

Resumen

Para muchos casos de uso, la función POSIX isatty() es todo lo que se necesita para detectar si stdin está conectado a un terminal. Un ejemplo mínimo:

 #include  #include  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 siguiente sección compara diferentes métodos que se pueden usar si se deben probar diferentes grados de interactividad.

Métodos en detalle

Existen varios métodos para detectar si un progtwig se está ejecutando de forma interactiva. La siguiente tabla muestra una descripción general:

 cmd \ method ctermid open isatty fstat
 -------------------------------------------------- ----------
 .test / dev / tty OK SÍ S_ISCHR
 ./test ≺ test.cc / dev / tty OK NO S_ISREG
 gato test.cc |  .test / dev / tty OK NO S_ISFIFO
 echo ./test |  en este momento / dev / tty FAIL NO S_ISREG

Los resultados son de un sistema Ubuntu Linux 11.04 usando el siguiente progtwig:

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

Dispositivo termico

Si la sesión interactiva necesita ciertas capacidades, puede abrir el dispositivo terminal y (temporalmente) configurar los atributos de terminal que necesita a través de tcsetattr() .

Ejemplo de Python

El código de Python que decide si el intérprete se ejecuta interactivamente usa isatty() . La función PyRun_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); 

llama a 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 "" or "???". */ int Py_FdIsInteractive(FILE *fp, const char *filename) { if (isatty((int)fileno(fp))) return 1; 

que llama isatty() .

Conclusión

Hay diferentes grados de interactividad. Para comprobar si stdin está conectado a una tubería / archivo o una terminal real isatty() es un método natural para hacerlo.

Llamar a stat () o fstat () y ver si S_IFIFO está configurado en st_mode.

Probablemente están verificando el tipo de archivo que “stdin” es con fstat, algo como esto:

 struct stat stats; fstat(0, &stats); if (S_ISCHR(stats.st_mode)) { // Looks like a tty, so we're in interactive mode. } else if (S_ISFIFO(stats.st_mode)) { // Looks like a pipe, so we're in non-interactive mode. } 

Pero, ¿por qué preguntarnos? Python es de código abierto. Puedes ir a ver lo que hacen y saber con certeza:

http://www.python.org/ftp/python/2.6.2/Python-2.6.2.tar.bz2

Espero que ayude,

Eric Melski

Puede invocar stat(0, &result) y verificar !S_ISREG( result.st_mode ) . Eso es Posix, no C / C ++, sin embargo.

En Windows puede usar GetFileType.

 HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); DWORD type = GetFileType(hIn); switch (type) { case FILE_TYPE_CHAR: // it's from a character device, almost certainly the console case FILE_TYPE_DISK: // redirected from a file case FILE_TYPE_PIPE: // piped from another program, a la "echo hello | myprog" case FILE_TYPE_UNKNOWN: // this shouldn't be happening... }