2009-09-17 3 views
12

Я просматриваю код утилиты «less», а именно, как он вводит клавиатуру. Интересно, что на линии 80 ttyin.c, он задает дескриптор файла для чтения из:Меньше получает ввод клавиатуры от 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 STDERR? Если да, то WTH ?! Я думал, что ввод с клавиатуры был отправлен через stdin.

Интересно, что даже если вы ls -l * | less, после того, как файл загрузится, вы можете использовать клавиатуру для прокрутки вверх и вниз, но если вы делаете ls -l * | vi, то VI будет кричать на вас, потому что он не читает из стандартного ввода , Какая идея? Как я попал на эту странную новую землю, где stderr - это способ сообщить об ошибках на экран и прочитать с клавиатуры? Я не думаю, что я в Канзасе больше ...

+0

BTW, если вы пишете 'ls -l * | vim -', vim будет выполнять подобную магию. – ephemient

ответ

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 

При входе в систему на промежуточном терминале все три стандартных дескриптора файла указывают на одно и то же: ваш 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 и писать 1 и 2. Однако ничто не мешает нам поступать иначе.

Когда оболочка запускает ls -l * | less, он создает трубу из ls «s дескриптор файла 1 в less» дескриптора файла с 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 был изменен – сейчас less выходит сразу же, потому что он выводит на TTY, но он не может получить никакого ввода пользователя.

+3

+1, очень полный. –

+0

О, я вижу это сейчас. Поскольку stderr - это не что иное, как дескриптор файлового дескриптора, который фактически подключен к терминалу, он может читать или писать из него, как ему заблагорассудится. ЭТО КРУТО! Спасибо, эфемерный. – Michael

+0

Не мог бы файл дескриптор '2' быть открыт только для записи? –

2

Ну ... сначала вы, кажется, пропустили вызов open(), который открывает '/ dev/tty'. Он использует только дескриптор файла 2, если вызов open() завершается с ошибкой. В стандартной Linux-системе и, возможно, во многих Unices существует «/ dev/tty» и вряд ли вызовет сбой.

Во-вторых, комментарий в верхней части обеспечивает ограниченное количество объяснений, почему они падают обратно в дескрипторе файла 2. Я думаю, что stdin, stdout и stderr в значительной степени связано с «/ Dev/TTY /» во всяком случае, если не перенаправлено. А так как наиболее распространенные перенаправления для stdin и/или stdout (по трубопроводам или </>), но реже для stderr, вероятность того, что использование stderr, скорее всего, будет по-прежнему подключаться к «клавиатуре».

+0

Причина использования stderr в том, что stdin/stdout, скорее всего, будут трубами, созданными нерестилирующей оболочкой. Трубопровод в или из меньшего количества - это заглушка, но он работает. Но перенаправление stderr меньшей команды специально имеет мало значения и вряд ли будет выполнено. Таким образом, делая ставку на то, что stderr «действительно», терминальное устройство является разумным догадкой. –

1

Тот же вопрос с ответом в конечном счете от человека, который спросил его, находится на linuxquestions, хотя они приводят немного другой источник от less. И нет, я не понимаю, большинство из них, так что я не могу за этого :)

-2

Это, как представляется, Linux конкретные функциональные возможности, которые посылает ввод с клавиатуры FD 2.

+1

Блаженно ложно. Попробуйте это в любой другой UNIX. – ephemient