Resumo
Para muitos casos de uso, a função POSIXisatty()
é tudo o que é necessário para detectar se stdin está conectado a um terminal. Um exemplo 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;
}
A seção a seguir compara diferentes métodos que podem ser usados se diferentes graus de interatividade tiverem que ser testados.
Métodos em Detalhe
Existem vários métodos para detectar se um programa está sendo executado interativamente. A tabela a seguir mostra uma visão geral:
cmd \ method ctermid open isatty fstat
――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ―――――――――――
./test / dev / tty OK SIM S_ISCHR
./test ≺ 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 <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
Se a sessão interativa precisa de certos recursos, você pode abrir o dispositivo de terminal e (temporariamente) definir os atributos de terminal que você precisa via tcsetattr()
.
Exemplo Python
O código Python que decide se o interpretador é executado interativamente usa isatty()
. A funçãoPyRun_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);
chamadas 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 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.