Stdin'in bir terminal mi yoksa boru mu olduğunu tespit et?


118

pythonHiçbir argüman olmadan terminalden " " çalıştırdığımda Python etkileşimli kabuğunu getiriyor.

cat | pythonTerminalden " " çalıştırdığımda etkileşimli modu başlatmıyor. Her nasılsa herhangi bir girdi almadan bir boruya bağlı olduğunu tespit etmiştir.

C veya C ++ veya Qt'de benzer bir algılamayı nasıl yaparım?


7
İstediğiniz şey, stdin'in bir boru olup olmadığını algılamak değil, stdin / stdout'un bir terminal olup olmadığını tespit etmektir.
Juliano

Yanıtlar:


137

Kullanım 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");

(Pencereler onlar çizgi öneki ediyoruz: _isatty, _fileno)


13
+1: stdin bir boru olabilir veya bir dosyadan yönlendirilebilir. O takdirde daha iyi kontrol etmek olduğunu bunun olup olmadığını kontrol etmek daha interaktif değil .
John Kugelman

51
POSIX'te hiçbir şey yoktur io.hve isatty()eklemeniz gerekir unistd.h.
maxschlepzig

Takip eden soru: stdin bir tty değilse, aktarılan içerikler nasıl okunur? stackoverflow.com/q/16305971/96656
Mathias Bynens

Not: -çıkışınızın bir tty olup olmadığını görmek istiyorsanız stdout'u (STDOUT_FILENO) kontrol etmeniz gerekir, eğer içine borulu ise çıktıyı bastırmak istemeniz durumunda less.
Coroos

71

özet

Çoğu kullanım durumu için POSIX işlevi isatty(), stdin'in bir terminale bağlı olup olmadığını saptamak için gereken tek şeydir. Minimal bir örnek:

#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şağıdaki bölüm, farklı etkileşim derecelerinin test edilmesi gerektiğinde kullanılabilecek farklı yöntemleri karşılaştırmaktadır.

Ayrıntılı Yöntemler

Bir programın etkileşimli olarak çalışıp çalışmadığını algılamanın birkaç yöntemi vardır. Aşağıdaki tablo bir genel bakış göstermektedir:

cmd \ method ctermid açık isatty fstat
-------------------------------------------------- ----------
./test / dev / tty TAMAM EVET S_ISCHR
./test ≺ test.cc / dev / tty TAMAM HAYIR S_ISREG
kedi test.cc | ./test / dev / tty TAMAM HAYIR S_ISFIFO
yankı ./test | şu anda / dev / tty BAŞARISIZ HAYIR S_ISREG

Sonuçlar, aşağıdaki programı kullanan bir Ubuntu Linux 11.04 sisteminden alınmıştır:

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

Etkileşimli oturumun belirli yeteneklere ihtiyacı varsa, terminal cihazını açabilir ve (geçici olarak) ihtiyacınız olan terminal özelliklerini ayarlayabilirsiniz tcsetattr().

Python Örneği

Tercüman etkileşimli çalışır karar verir Python kodu kullanır isatty(). İşlevPyRun_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);

aramalar 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;

hangi aramalar isatty().

Sonuç

Farklı derecelerde etkileşim vardır. stdinBir boruya / dosyaya veya gerçek bir terminale bağlı olup olmadığını kontrol etmek isatty(), bunu yapmak için doğal bir yöntemdir.


6

Muhtemelen "stdin" in fstat ile olduğu dosya türünü kontrol ediyorlardır, buna benzer bir şey:

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

Elbette Python açık kaynak kodludur, bu yüzden ne yaptıklarına bakabilir ve kesin olarak bilebilirler:

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


4

Windows'ta GetFileType'ı kullanabilirsiniz.

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 () veya fstat () çağırın ve S_IFIFO'nun st_mode'da ayarlanıp ayarlanmadığına bakın.


3

Arayıp stat(0, &result)kontrol edebilirsiniz !S_ISREG( result.st_mode ). Bu Posix, C / C ++ değil.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.