Detectar se stdin é um terminal ou tubo?

Quando eu executo ” python ” do terminal sem argumentos, ele traz o shell interativo do Python.

Quando eu executo ” cat | python ” do terminal, ele não inicia o modo interativo. De alguma forma, sem receber nenhuma input, ele detectou que está conectado a um pipe.

Como eu faria uma detecção semelhante em C ou C ++ ou 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"); 

(Nas janelas eles são prefixados com sublinhados: _isatty , _fileno )

Resumo

Para muitos casos de uso, a function isatty() é tudo o que é necessário para detectar se stdin está conectado a um terminal. Um exemplo 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; } 

A seção a seguir compara methods diferentes que podem ser usados ​​se diferentes graus de interatividade tiverem que ser testados.

Métodos detalhados

Existem vários methods para detectar se um programa está sendo executado de forma interativa. A tabela a seguir mostra uma visão geral:

 cmd \ método ctermid open isatty fstat
 ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ――――――――――
 ./test / dev / tty OK SIM S_ISCHR
 ./teste ≺ test.cc / dev / tty OK NÃO S_ISREG
 cat test.cc |  ./test / dev / tty OK NÃO S_ISFIFO
 echo ./test |  agora / dev / tty FAIL NO S_ISREG

Os resultados são de um sistema Ubuntu Linux 11.04 usando o seguinte programa:

 #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 Termimal

Se a session interativa precisar de determinados resources, você poderá abrir o dispositivo terminal e (temporariamente) definir os atributos do terminal necessários por meio de tcsetattr() .

Exemplo de Python

O código Python que decide se o intérprete é executado de forma interativa usa isatty() . A function 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); 

chama 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 chama isatty() .

Conclusão

Existem diferentes graus de interatividade. Para verificar se stdin está conectado a um pipe / arquivo ou um terminal real isatty() é um método natural para fazer isso.

Chame stat () ou fstat () e veja se S_IFIFO está definido em st_mode.

Provavelmente eles estão verificando o tipo de arquivo que “stdin” está com fstat, algo assim:

 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. } 

Mas por que nos perguntar? Python é código aberto. Você pode simplesmente ver o que eles fazem e saber com certeza:

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

Espero que ajude,

Eric Melski

Você pode chamar stat(0, &result) e verificar !S_ISREG( result.st_mode ) . Isso é Posix, não C / C ++, no entanto.

No Windows, você pode 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... }