2010-09-06 28 views
7

Các tập tin C sau đây đưa ra một kết quả không có thật khi NUL được cấp nước tập trung với nó:Detect mô tả tập tin NUL (isatty là giả mạo)

int main() 
{ 
    printf("_isatty = %d\n", _isatty(0)); 
} 

kết quả là:

C:\Users\Edward\Dev\nulltest> test.exe < NUL 
_isatty = 64 

Tôi khá chắc chắn NUL (aka/dev/null) không phải là thiết bị đầu cuối! Vì vậy, tôi cần phải phát hiện theo cách khác cho dù bộ mô tả tập tin có tương ứng với NUL hay không. Số không có ý nghĩa cụ thể; Tôi nhìn thấy nó khi tôi thực sự có một thiết bị đầu cuối kèm theo.

Tôi nên làm gì? This question đề xuất sử dụng hàm sơ bộ không có giấy tờ để lấy tên cơ bản, có lẽ so sánh nó với NUL, nhưng điều đó cảm thấy ít hơn lý tưởng đối với tôi. Có cách nào tốt hơn?

P.S. Điều này sẽ giúp giải quyết this GHC bug.

+0

Chỉ cần ra khỏi sự quan tâm (và tôi không nói rằng những gì bạn đang làm là sai): tại sao bạn quan tâm nơi đầu vào của sắp tới từ? – paxdiablo

+0

Có nhiều ứng dụng thực hiện những việc khác nhau khi chúng phát hiện thiết bị đầu cuối. Ví dụ, nếu bạn gõ 'python', nó sẽ đi vào chế độ tương tác, nhưng 'echo' in \ "bar \" "| python 'sẽ không hiển thị bất kỳ màn hình khởi tạo nào. –

+0

Tôi _hate_ những chương trình :-) – paxdiablo

Trả lời

4

Từ msdn:

_isatty trả về giá trị khác không nếu mô tả được liên kết với một thiết bị nhân vật. Nếu không, _isatty trả về 0.

NUL giống như/dev/null trên Unix, đó là thiết bị char.

Lưu ý rằng trên Linux, isatty là khác nhau:

Các isatty() kiểm tra chức năng dù fd là một bộ mô tả tập tin mở ám đến một thiết bị đầu cuối.

Điều bạn có thể làm là thử so sánh STDIN_FILENO (0) với $ {cwd}/NUL (sử dụng stat hoặc stat).

Cập nhật:

int ret = GetFileType(GetStdHandle(STD_INPUT_HANDLE)); 

Nó sẽ trở lại FILE_TYPE_CHAR cho NUL hoặc tty.

Xem tài liệu GetFileType cho các giá trị khác. Bạn có thể phát hiện tệp/thiết bị/đường ống.

Cập nhật cuối cùng:

Sử dụng GetConsoleMode cho đầu vào và GetConsoleScreenBufferInfo cho đầu ra.

CONSOLE_SCREEN_BUFFER_INFO sbi; 
DWORD mode; 
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode)) 
    fprintf(stderr, "not console\n"); 
else 
    fprintf(stderr, "console\n"); 
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi)) 
    fprintf(stderr, "not console\n"); 
else 
    fprintf(stderr, "console\n"); 
+0

Thú vị! Điều đó ngụ ý rằng chúng ta không nên thực sự sử dụng đẳng cấp để phát hiện nếu có một thiết bị đầu cuối. Có chức năng tương đương trên Windows không? –

+0

_isatty bị lỗi, nó sẽ phát hiện nếu bạn đang sử dụng một thiết bị đầu cuối, không phải nếu fd là một thiết bị ký tự. Tôi không chắc chắn cách tốt nhất để làm điều đó trên cửa sổ là gì. Bạn có thể thử kiểm tra việc thực hiện đẳng cấp Cygwin/mingway. Bạn cũng có thể tạo một danh sách đen bao bọc $ (CWD)/NUL, vì nó có lẽ là thiết bị ký tự duy nhất bạn sẽ dễ dàng sử dụng trên các cửa sổ. – iksaif

+0

Ok, tôi đã tìm ra giải pháp thực sự, tôi đã cập nhật câu trả lời của mình – iksaif

-2

Bạn có thể sử dụng fstat trên bộ mô tả tệp và so sánh thành viên thiết bị của cấu trúc stat kết quả với điều đó cho /dev/null và xem chúng có khớp không.

+1

Không hoạt động. _stat luôn trả về 2, trong khi _fstat luôn trả về 0. –

0

Đây là giải pháp khả thi, nhưng tôi không tin rằng nó hoạt động mọi lúc.Tôi tin rằng nó sẽ làm việc đối với trường hợp cụ thể của một bộ mô tả tập tin NUL:

 
int real_isatty(int fd) { 
    DWORD st; 
    HANDLE h; 
    if (!_isatty(fd)) { 
     /* TTY must be a character device */ 
     return 0; 
    } 
    h = (HANDLE)_get_osfhandle(fd); 
    if (h == INVALID_HANDLE_VALUE) { 
     /* Broken handle can't be terminal */ 
     return 0; 
    } 
    if (!GetConsoleMode(h, &st)) { 
     /* GetConsoleMode appears to fail when it's not a TTY. */ 
     return 0; 
    } 
    return 1; 
} 
Các vấn đề liên quan