Resumen
Para muchos casos de uso, la función POSIXisatty()
es todo lo que se necesita para detectar si stdin está conectado a un terminal. Un ejemplo mínimo:
#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 siguiente sección compara diferentes métodos que se pueden utilizar si se tienen que probar diferentes grados de interactividad.
Métodos en detalle
Existen varios métodos para detectar si un programa se está ejecutando de forma interactiva. La siguiente tabla muestra una descripción general:
cmd \ método ctermid abierto isatty fstat
―――――――――――――――――――――――――――――――――――――――――――――― ――――――――――
./test / dev / tty OK SÍ S_ISCHR
./test ≺ test.cc / dev / tty OK NO S_ISREG
cat test.cc | ./test / dev / tty OK NO S_ISFIFO
echo ./test | ahora / dev / tty FAIL NO S_ISREG
Los resultados son de un sistema Ubuntu Linux 11.04 usando el siguiente programa:
#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;
}
Dispositivo termimal
Si la sesión interactiva necesita ciertas capacidades, puede abrir el dispositivo terminal y (temporalmente) establecer los atributos del terminal que necesita a través de tcsetattr()
.
Ejemplo de Python
El código Python que decide si el intérprete se ejecuta de forma interactiva usa isatty()
. La funciónPyRun_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);
llamadas 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;
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.