stdin이 터미널인지 파이프인지 감지합니까?


118

python인수없이 터미널에서 " "을 실행 하면 Python 대화 형 셸이 나타납니다.

cat | python터미널에서 " "을 실행하면 대화 형 모드가 시작되지 않습니다. 어떻게 든 입력을받지 않고 파이프에 연결되어 있음을 감지했습니다.

C, C ++ 또는 Qt에서 유사한 감지를 어떻게 수행합니까?


7
원하는 것은 stdin이 파이프인지 감지하지 않고 stdin / stdout이 터미널인지 감지하는 것입니다.
Juliano

답변:


137

사용 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)


13
+1 : stdin은 파이프이거나 파일에서 리디렉션 될 수 있습니다. 이 경우 더 나은 확인하는 것입니다 이 있는지 확인하는 것보다 대화 형 없습니다 .
John Kugelman

51
POSIX 거기에 더없는 io.h과에 대해 isatty()당신은 포함해야합니다 unistd.h.
maxschlepzig 2011 년

후속 질문 : stdin이 tty가 아닌 경우 파이프 된 내용을 읽는 방법은 무엇입니까? stackoverflow.com/q/16305971/96656
Mathias Bynens 2013

참고 : -output-이 tty인지 여부를 확인하려면 stdout (STDOUT_FILENO)을 확인해야합니다 less.
Coroos

71

요약

많은 사용 사례에서 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 isatty fstat 열기
――――――――――――――――――――――――――――――――――――――――――――――――― ――――――――――
./test / dev / tty 확인 예 S_ISCHR
./test ≺ test.cc / dev / tty OK NO S_ISREG
고양이 test.cc | ./test / dev / tty OK NO S_ISFIFO
echo ./test | 현재 / 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()자연스러운 방법입니다.


5

아마도 그들은 다음과 같이 "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.
}

물론 파이썬은 오픈 소스이므로 그들이하는 일을보고 확실히 알 수 있습니다.

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


4

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

3

stat () 또는 fstat ()를 호출하고 S_IFIFO가 st_mode에 설정되어 있는지 확인합니다.


3

전화 stat(0, &result)하여 !S_ISREG( result.st_mode ). 그래도 C / C ++가 아니라 Posix입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.