2009-09-17 34 views
12

Tôi đang xem mã để tiện ích 'ít' hơn, cụ thể là cách nó được nhập bằng bàn phím. Thật thú vị, trên dòng 80 của ttyin.c, nó đặt bộ mô tả tệp để đọc từ:Ít được nhập bằng bàn phím từ stderr?

 /* 
     * Try /dev/tty. 
     * If that doesn't work, use file descriptor 2, 
     * which in Unix is usually attached to the screen, 
     * but also usually lets you read from the keyboard. 
     */ 
    #if OS2 
     /* The __open() system call translates "/dev/tty" to "con". */ 
     tty = __open("/dev/tty", OPEN_READ); 
    #else 
     tty = open("/dev/tty", OPEN_READ); 
    #endif 
     if (tty < 0) 
      tty = 2; 

Không phải là bộ mô tả tập tin 2 stderr? Nếu vậy, WTH ?! Tôi nghĩ rằng đầu vào bàn phím đã được gửi thông qua stdin.

Điều thú vị là ngay cả khi bạn làm ls -l * | less, sau khi tệp kết thúc tải, bạn vẫn có thể sử dụng bàn phím để cuộn lên và xuống, nhưng nếu bạn làm ls -l * | vi thì vi sẽ hét vào bạn vì nó không đọc từ stdin . Ý tưởng lớn là gì? Làm thế nào tôi đã kết thúc trong đất mới lạ này, nơi stderr là cả hai cách để báo cáo lỗi cho màn hình và đọc từ bàn phím? Tôi không nghĩ rằng tôi đang ở Kansas nữa ...

+0

BTW, nếu bạn viết 'ls -l * | vim -', vim sẽ thực hiện phép thuật tương tự. – ephemient

Trả lời

19
 
$ ls -l /dev/fd/ 
lrwx------ 1 me me 64 2009-09-17 16:52 0 -> /dev/pts/4 
lrwx------ 1 me me 64 2009-09-17 16:52 1 -> /dev/pts/4 
lrwx------ 1 me me 64 2009-09-17 16:52 2 -> /dev/pts/4 

Khi đăng nhập tại một thiết bị đầu cuối tương tác, tất cả ba mô tả tập tin tiêu chuẩn đều trỏ đến cùng một điều: TTY của bạn (hoặc giả TTY).

 
$ ls -fl /dev/std{in,out,err} 
lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdin -> fd/0 
lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdout -> fd/1 
lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stderr -> fd/2 

Theo quy ước, chúng ta đọc từ 0 và ghi vào 12. Tuy nhiên, không có gì ngăn cản chúng tôi làm khác.

Khi vỏ của bạn chạy ls -l * | less, nó tạo ra một đường ống từ ls 's mô tả tập tin 1 để less' mô tả của tập tin 0. Rõ ràng, less không còn có thể đọc đầu vào bàn phím của người dùng từ bộ mô tả tập tin 0 – nhưng nó sẽ cố gắng lấy lại TTY dù có thể.

Nếu less chưa được tách ra khỏi thiết bị đầu cuối, open("/dev/tty") sẽ cấp cho nó TTY.

Tuy nhiên, trong trường hợp không thành công ... bạn có thể làm gì? less thực hiện một nỗ lực cuối cùng để nhận TTY, giả sử rằng bộ mô tả tập tin 2 được gắn vào cùng một điều mà bộ mô tả tập tin 0 sẽ được gắn vào, nếu nó không được chuyển hướng.

Đây không phải là failproof:

 
$ ls -l * | setsid less 2>/dev/null 

Ở đây, less được đưa ra phiên riêng của mình (do đó nó không còn là một phần của nhóm quá trình hoạt động của thiết bị đầu cuối, gây open("/dev/tty") thất bại), và tập tin của mình bộ mô tả 2 đã được thay đổi – ngay bây giờ less thoát ngay lập tức vì nó xuất ra TTY nhưng không thể nhận được bất kỳ thông tin nhập nào của người dùng.

+3

+1, rất hoàn chỉnh. –

+0

Ồ, tôi thấy nó ngay bây giờ. Bởi vì stderr là không có gì hơn là juts một mô tả tập tin đó là thực sự kết nối với thiết bị đầu cuối, nó có thể đọc hoặc viết từ nó như nó vui lòng. CÓ MÁT! Cảm ơn bạn, ephemient. – Michael

+0

Chẳng phải tệp mô tả '2' chỉ mở để viết chứ? –

2

Vâng ... trước hết, bạn dường như thiếu cuộc gọi open() mở '/ dev/tty'. Nó chỉ sử dụng bộ mô tả tập tin 2 nếu cuộc gọi để mở() không thành công. Trên một hệ thống Linux chuẩn, và có lẽ nhiều Unices, '/ dev/tty' tồn tại và không có khả năng gây ra lỗi.

Thứ hai, comment ở phía trên cung cấp một số lượng hạn chế giải thích là tại sao họ rơi trở lại để mô tả tập tin 2. Tôi đoán là stdin, stdout, và stderr được khá nhiều kết nối với '/ dev/tty /' dù sao, trừ khi được chuyển hướng. Và kể từ khi chuyển hướng phổ biến nhất cho stdin và/hoặc stdout (thông qua đường ống hoặc </>), nhưng ít thường xuyên hơn cho stderr, tỷ lệ cược là sử dụng stderr có nhiều khả năng vẫn sẽ được kết nối với "bàn phím".

+0

Lý do sử dụng stderr là stdin/stdout có nhiều khả năng là đường ống được tạo ra bởi vỏ sinh sản. Đường ống vào hoặc ra khỏi ít hơn là một noop, nhưng không hoạt động. Nhưng chuyển hướng stderr của một lệnh ít hơn đặc biệt có ít giá trị và không có khả năng được thực hiện. Vì vậy, cá cược rằng stderr là "thực sự" thiết bị đầu cuối là một dự đoán hợp lý. –

1

Câu hỏi tương tự với câu trả lời cuối cùng từ người đã hỏi là trên linuxquestions mặc dù họ trích dẫn nguồn hơi khác một chút từ less. Và không, tôi không hiểu nhất của nó vì vậy tôi không thể giúp vượt ra ngoài đó :)

-2

Nó dường như là Linux chức năng cụ thể mà sẽ gửi đầu vào bàn phím để FD 2.

+1

Blatantly false. Hãy thử điều này trên bất kỳ UNIX nào khác. – ephemient

Các vấn đề liên quan