Як "менше" приймає дані з stdin, поки ще може читати команди від користувача?


47

Як і більшість з вас багато разів, зручно переглядати довгий текст, використовуючи less:

some_command | less

Тепер його stdin з'єднаний з трубою (FIFO). Як він все ще може читати команди, такі як вгору / вниз / вихід?


15
lessзчитує дані, що відображаються з stdin, і зчитує команди з tty. Вони різні речі.
Вільям Перселл

2
@WilliamPursell Так, я знаю. Але є лише один стандартний вхідний потік, правда?
iBug

4
Так, є один вхідний потік і один tty. lessчитає дані зі stdin та команди з tty.
Вільям Перселл

Відповіді:


52

Як згадував Вільям Персел , lessчитає натискання клавіші користувача з терміналу. Він явно відкриває /dev/ttyкеруючий термінал; що дає йому дескриптор файлу, окремий від стандартного вводу, з якого він може читати інтерактивний ввід користувача. Він може одночасно зчитувати дані для відображення зі свого стандартного введення, якщо необхідно. (При необхідності він також може писати безпосередньо в термінал.)

Ви можете бачити це, запускаючи

some_command | strace -o less.trace -e open,read,write less

Перемістіть вхід, вийдіть lessі подивіться на вміст less.trace: ви побачите його відкритим /dev/tty, і прочитайте з дескриптора файлів 0 і того, що повернуто при відкритті /dev/tty(вірогідно 3).

Це звичайна практика для програм, які хочуть переконатися, що вони читають і записують в термінал. Одним із прикладів є SSH, наприклад, коли він запитує пароль або пароль.

Як пояснив на Шили , якщо /dev/ttyне може бути відкритий, lessбуде зчитуватися з стандартної помилки (дескриптор файлу 2). lessВикористання /dev/ttyбуло введено у версії 177, випущеній 2 квітня 1991 року.

При спробі запуску cat /dev/tty | less, як і запропонував на Хаген фон Eitzen , lessдосягне успіху у відкритті , /dev/ttyале не отримаєте жодної інформації від нього до тих пір , catзакриває його. Так ви побачите екран порожнім, і більше нічого, поки не натиснете, CtrlCщоб вбити cat(або вбити його якось іншим способом); то lessпокаже все, що ви ввели під час catзапуску, і дозволить вам керувати ним.


4
@HagenvonEitzen Ваш комп'ютер вибухне! Це як спосіб, коли Кірк і Спок звалили андроїди Мадда.
Бармар

7
@HagenvonEitzen Wow Подвійне марне використання кота . Я вражений.
Ендрю Генле

8
@grawity Я думаю, що питання Ендрю в тому, що cat blah |його можна замінити < blah, і навіть це непотрібно в цьому випадку, оскільки less blahпрацює також (добре, less -f /dev/tty). Але читання з /dev/ttyце трохи особливого випадку, і всі три варіанти ( cat /dev/tty | less, less < /dev/ttyі less -f /dev/tty) дають різні результати.
Стівен Кітт

1
Чи / dev / tty завжди якось вказує на потрібне місце? Я думаю, вам зазвичай потрібно використовувати / dev / ptsX?
StarWeaver

2
@StarWeaver перегляньте це питання про різницю між /dev/ttyта /dev/pts/....
Стівен Кітт

26

UNIX надає два способи зчитування вводу користувачів під час перенаправлення stdin:

  • Оригінальний метод - це читати з stderr . Stderr відкритий для написання та читання, і це все ще згадується в POSIX.

  • Пізніші версії UNIX зробили (близько 1979 р.) Доданий /dev/ttyдрайвер, що дозволяє відкривати керуючу систему процесу. Оскільки існують процеси без контролю tty, можливо, спроба відкрити /dev/ttyне вдалася . Отже, дружнє письмове програмне забезпечення має відступ до початкового методу, а потім намагається читати з stderr.


11
Читати з stderr? Дізналися чогось нового.
iBug

1
Я радий, що хтось пам’ятає старі способи.
Джошуа

3
Чи є причиною того, що stderr використовується для читання, тому що він найменш ймовірно переспрямований? Я не бачу ніякої іншої різниці між ним та stdout (або для цього mater stdin перед перенаправленням).
ctrl-alt-delor

4
Так, це тому, що це дескриптор файлу, який має найменший шанс для переадресації.
schily

@ ctrl-alt-delor: Для оболонок було / типово працювати зі stdin, stdout та stderr, але все це dup()схожі на те ж опис файлу, але всі вони відкриті в tty. (Мабуть, POSIX все ще вимагає або пропонує (ця відповідь не говорить), що stderr - це FD для читання / запису, а не відкривається чимось подібним open("/dev/ttyS0", O_WRONLY). Читання stderr не вдасться у такому випадку.)
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.