Обнаруживать, является ли stdin терминалом или трубой?
Когда я выполняю "python
" из терминала без аргументов, он вызывает интерактивную оболочку Python.
Когда я выполняю "cat | python
" с терминала, он не запускает интерактивный режим. Так или иначе, не получив никакого ввода, он обнаружил, что он подключен к трубе.
Как бы я сделал подобное обнаружение в C или С++ или Qt?
Ответы
Ответ 1
Используйте 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");
(В окнах они имеют префикс с символами подчеркивания: _isatty
, _fileno
)
Ответ 2
Резюме
Для многих случаев использования 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;
}
Терминальное устройство
Если интерактивный сеанс требует определенных возможностей, вы можете открыть
терминальное устройство и (временно) установить атрибуты терминала, которые вам нужны
через tcsetattr()
.
Пример Python
Код 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
подключенный к трубе/файлу или реальному терминалу isatty()
, является естественным методом для
сделайте это.
Ответ 3
Вызвать stat() или fstat() и посмотреть, установлен ли S_IFIFO в st_mode.
Ответ 4
Вероятно, они проверяют тип файла "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
Ответ 5
Вы можете позвонить stat(0, &result)
и проверить !S_ISREG( result.st_mode )
. Это Posix, а не C/С++, хотя.
Ответ 6
В Windows вы можете использовать GetFileType.
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD type = GetFileType(hIn);
switch (type) {
case FILE_TYPE_CHAR:
// it 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...
}