Меньше получает ввод с клавиатуры от stderr?
-
10-07-2019 - |
Вопрос
Я смотрю на код утилиты 'less', особенно на то, как он получает ввод с клавиатуры. Интересно, что в строке 80 файла ttyin.c он устанавливает дескриптор файла для чтения из:
/*
* 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 ?! Я думал, что ввод с клавиатуры был отправлен через стандартный ввод.
Интересно, что даже если вы сделаете ls -l * | less
, после завершения загрузки файла вы все равно сможете использовать клавиатуру для прокрутки вверх и вниз, но если вы сделаете ls -l * | vi
, то vi будет кричать на вас, потому что это не так читать со стандартного ввода. Что за большая идея? Как я оказался в этой странной новой стране, где stderr - это способ сообщать об ошибках на экран и читать с клавиатуры? Я не думаю, что я в Канзасе больше ...
Решение
$ 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
файлового дескриптора less
в open("/dev/tty")
файловый дескриптор <=>. Очевидно, <=> больше не может читать ввод с клавиатуры пользователя из файлового дескриптора <=> & # 8211; он пытается вернуть TTY как может.
Если <=> не был отсоединен от терминала, <=> предоставит ему TTY.
Однако, в случае неудачи ... что вы можете сделать? <=> делает последнюю попытку получения TTY, предполагая, что дескриптор файла <=> присоединен к тому же объекту, к которому был бы прикреплен дескриптор файла <=>, если бы он не был перенаправлен.
Это не является отказоустойчивым:
$ ls -l * | setsid less 2>/dev/null
Здесь <=> присваивается собственный сеанс (поэтому он больше не является частью активной группы процессов терминала, что приводит к сбою <=>), а его дескриптор файла <=> был изменен & # 8211; теперь <=> немедленно завершается, поскольку он выводится на TTY, но не может получить какой-либо пользовательский ввод.
Другие советы
Ну ... во-первых, вы, кажется, пропустили вызов open()
, который открывает '/ dev / tty'. Он использует файловый дескриптор 2 только в случае сбоя вызова open (). В стандартной системе Linux и, возможно, во многих Unix'ах, существует / dev / tty, который вряд ли вызовет сбой.
Во-вторых, комментарий вверху дает ограниченное количество объяснений, почему они возвращаются к файловому дескриптору 2. Я предполагаю, что stdin
, stdout
и stderr
в значительной степени связаны с '/ В любом случае, dev / tty / ', если не перенаправлен. А поскольку наиболее распространенные перенаправления для для stdin и / или stdout (через трубопроводы или <
/ >
), но реже для <=>, вероятность того, что использование <=> все еще будет подключено, скорее всего, будет на & клавиатуру & ".
Тот же вопрос с ответом, в конечном счете, от человека, который его задал, находится на linuxquestions , хотя они цитируют немного другой источник из less
. И нет, я не понимаю большинство из них, поэтому я не могу помочь в этом:)
Похоже, это специфическая функция Linux, которая отправляет ввод с клавиатуры на FD 2.