138

ターミナルから引数なしで" " を実行するpythonと、Python インタラクティブ シェルが起動します。

ターミナルから" " を実行するとcat | python、インタラクティブ モードが起動しません。どういうわけか、入力を取得せずに、パイプに接続されていることを検出しました。

C、C++、または Qt で同様の検出を行うにはどうすればよいですか?

4

6 に答える 6

84

概要

多くのユースケースでは、標準入力が端末に接続されているかどうかを検出するために必要なのはPOSIX関数だけです。isatty()最小限の例:

#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>
int main() {
  char tty[L_ctermid+1];
  ctermid(tty);
  printf("ID: %s\n", tty);
  int fd = open(tty, O_RDONLY);
  if (fd < 0) perror("Could not open terminal");
  else {
    printf("Opened terminal\n");
    struct termios term;
    int r = tcgetattr(fd, &term);
    if (r < 0) perror("Could not get attributes");
    else printf("Got attributes\n");
  }
  if (isatty(fileno(stdin))) printf("Is a terminal\n");
  else printf("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)) printf("S_ISCHR\n");
    else if (S_ISFIFO(stats.st_mode)) printf("S_ISFIFO\n");
    else if (S_ISREG(stats.st_mode)) printf("S_ISREG\n");
    else printf("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()、それを行う自然な方法です。

于 2011-09-29T18:10:02.320 に答える
8

おそらく、彼らは「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 はオープン ソースなので、Python が何をしているかを確認するだけで、確実に知ることができます。

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

于 2009-08-21T16:28:49.740 に答える
5

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...
}
于 2016-12-27T23:42:40.493 に答える
3

stat() または fstat() を呼び出し、S_IFIFO が st_mode に設定されているかどうかを確認します。

于 2009-08-21T16:24:30.017 に答える