2009-09-17 61 views
12

我正在看看'less'工具的代碼,特別是它如何獲得鍵盤輸入。有趣的是,ttyin.c的80線,它設置文件描述符閱讀:獲取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; 

是不是文件描述符2標準錯誤?如果是這樣,WTH ?!我認爲鍵盤輸入是通過stdin發送的。

有趣的是,即使你ls -l * | less,文件加載完畢後,你仍然可以使用鍵盤上下滾動,但如果這樣做ls -l * | vi,然後六將在罵你,因爲它不會從標準輸入讀取。什麼是大想法?我怎麼最終在這個陌生的新土地上出現了stderr既是向屏幕報告錯誤又從鍵盤讀取數據的方式?我不認爲我在堪薩斯州...

+0

順便說一句,如果你寫'ls -l * | vim -',vim會執行類似的魔法。 – ephemient 2011-02-07 14:31:59

回答

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 

當登錄Linux的特定功能在一個interative終端中,所有三個標準文件描述符指向相同的東西:你的TTY(或僞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 

按照慣例,我們從0讀取和寫入12。但是,沒有什麼能阻止我們做其他事情。

當你的shell中運行ls -l * | less,它創建從ls的文件描述符1less的文件描述符0管道。顯然,less不能再從文件描述符0 –讀取用戶的鍵盤輸入,但它嘗試獲取TTY,但它可以。

如果less尚未從終端分離,open("/dev/tty")將給它TTY。

但是,如果失敗...你能做什麼? less最後一次嘗試獲取TTY,假設文件描述符2附加到文件描述符0將被附加到的相同的東西,如果它沒有重定向。

不是 failproof:

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

這裏,less給出了自己的會話(所以它不再是終端的活動進程組的一部分,造成open("/dev/tty")失敗),並且其文件描述符2已被更改– now less立即退出,因爲它正在輸出到TTY,但它無法獲得任何用戶輸入。

+3

+1,非常完整。 – 2009-09-17 21:21:40

+0

哦,我現在看到它。由於stderr不過是一個實際連接到終端的文件描述符,它可以根據需要讀取或寫入它。這很酷!謝謝你,ephemient。 – Michael 2009-09-18 13:51:24

+0

雖然文件描述符'2'只能寫入,但是? – 2014-02-11 16:40:22

2

那麼......首先,你似乎錯過了打開'/ dev/tty'的open()調用。如果open()調用失敗,它只使用文件描述符2。在一個標準的Linux系統上,可能還有很多Unices,'/ dev/tty'存在並且不太可能導致失敗。

其次,在頂部的評論提供的解釋數量有限,爲什麼他們回落到文件描述符2。我的猜測是,stdinstdout,並stderr都非常連接到「的/ dev/tty的/」無論如何,除非重定向。由於stdin和/或標準輸出(通過管道或</>)最常見的重定向,但是對於stderr不太常見,使用stderr最有可能仍然連接到「鍵盤」的機率較低。

+0

使用stderr的原因是stdin/stdout更可能是由產卵shell創建的管道。進入或退出管道是一個noop,但確實有效。但重定向一個較少的命令stderr具有很小的價值,不可能完成。所以賭博stderr是「真的」終端設備是一個合理的猜測。 – 2009-09-17 21:55:45

1

同樣的問題最終來自提問者的回答是linuxquestions,儘管他們引用與less略有不同的來源。不,我不明白大多數,所以我不能幫助超出了:)

-2

這似乎是把鍵盤輸入到FD 2.

+1

公然錯誤。在任何其他UNIX上試試這個。 – ephemient 2009-09-17 21:09:14