[英]Detect if stdin is a terminal or pipe?
當我從終端不帶任何參數執行“ python
”時,它會彈出Python交互式shell。
當我從終端執行“ cat | python
”時,它不會啟動交互模式。 不知何故,它沒有得到任何輸入,就檢測到它已連接到管道。
我將如何在C或C ++或Qt中進行類似的檢測?
使用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;
}
如果交互式會話需要某些功能,則可以打開終端設備並通過tcsetattr()
臨時設置所需的終端屬性。
決定解釋程序是否以交互方式運行的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()
是這樣做的自然方法。
調用stat()或fstat()並查看是否在st_mode中設置了S_IFIFO。
可能他們正在使用fstat檢查“ stdin”所在的文件類型,如下所示:
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是開源的,因此您可以看看它們的作用並確定知道:
在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...
}
您可以調用stat(0, &result)
並檢查!S_ISREG( result.st_mode )
。 那是Posix,不是C / C ++。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.