Определите, является ли stdin терминалом или трубой?
когда я исполняю "python
" из терминала без аргументов он вызывает интерактивную оболочку Python.
когда я исполняю "cat | python
" из терминала он не запускает интерактивный режим. Каким-то образом, не получая никакого ввода, он обнаружил, что он подключен к трубе.
Как бы я сделал подобное обнаружение в C или C++ или Qt?
6 ответов:
использовать
isatty
:#include <stdio.h> #include <io.h> ... if (isatty(fileno(stdin))) printf( "stdin is a terminal\n" ); else printf( "stdin is a file or a pipe\n");
(в windows они имеют префикс с подчеркиванием:
_isatty
,_fileno
)
резюме
для многих случаев использования POSIX функции
isatty()
это все, что нужно, чтобы обнаружить, если stdin подключен к терминалу. Минимальный пример:#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; }
в следующем разделе сравниваются различные методы, которые могут быть использованы, если необходимо проверить различные степени интерактивности.
методы подробно
есть несколько методов, чтобы определить, если программа запущена интерактивно. Следующая таблица показывает обзор:
cmd\method ctermid open isatty fstat ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ./test /dev/tty OK YES S_ISCHR ./test ≺ test.cc /dev/tty OK NO S_ISREG cat test.cc | ./test /dev/tty OK NO S_ISFIFO echo ./test | at now /dev/tty FAIL NO S_ISREGрезультаты получены из системы Ubuntu Linux 11.04 с использованием следующей программы:
#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; }
устройства Termimal
если интерактивная сессия требует определенных возможностей, вы можете открыть терминальное устройство и (временно) набор необходимых атрибутов терминала через
tcsetattr()
.Пример Python
The код Python, который решает, работает ли интерпретатор интерактивно использует
isatty()
. Функция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);
звонки
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;
которых звонки
isatty()
.вывод
существуют различные степени интерактивности. Для проверки, если
stdin
is подключен к трубе / файлу или реальному терминалуisatty()
- это естественный способ сделать это.
вероятно, они проверяют тип файла, который "stdin" является с fstat, что-то вроде этого:
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. }
но зачем спрашивать нас? Python является открытым исходным кодом. Вы можете просто пойти посмотреть, что они делают, и знать наверняка:
http://www.python.org/ftp/python/2.6.2/Python-2.6.2.tar.bz2
надеюсь, что это поможет,
Эрик Melski
в Windows вы можете использовать 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... }