Чи безпечно вводити іншу команду в STDIN, коли попередня команда пише в STDOUT?


21

Можливо, на це відповіли раніше, я б вітав посилання на іншу відповідь ...

Якщо я виконую команду shell (у bashоболонці), наприклад:

make

Тоді, в той час як вихід з makeпрокрутки проходить STDOUTз makeкоманди, якщо я набираю make checkі натискаю enterдо того, як перша команда буде закінчена, коли makeкоманда остаточно завершиться, наступна команда make checkпідбере праворуч і запустить.

Мої питання:

  1. Це небезпечно робити?
  2. Чи є якісь потенційні несподівані поведінки від такого типу поспіху?
  3. Чому це працює так, як це робиться?

2
1. Я сподіваюся, що це не так ... Я роблю це вже роками!
Джон У. Сміт

Відповіді:


20

Це працює так, як це відбувається, тому що Unix є повнодуплексним. Як сказав Річі в системі обміну часом UNIX: Ретроспектива :

Одне, що здається тривіальним, але має дивовижну різницю після того, як ви звикли до цього, - це повнодуплексний термінал вводу / виводу разом з читанням вперед. Навіть незважаючи на те, що програми, як правило, спілкуються з користувачем через лінії, а не окремі символи, повнодуплексний термінал вводу / виводу означає, що користувач може вводити в будь-який час, навіть якщо система набирає текст назад, не боячись втратити чи загорнути символи . З попереднім читанням не потрібно чекати відповіді на кожен рядок. Хороший машиніст, який вводить документ, надзвичайно засмучений тим, що повинен зробити паузу перед початком кожного нового рядка; для тих, хто знає, що він хоче сказати, будь-яка повільність у відповіді стає психологічно підвищеною, якщо інформацію потрібно вводити побіжно, а не на повній швидкості.

[кінцева цитата]

Це, як кажуть, є деякі сучасні програми, які з'їдають або відкидають будь-які шпильки; sshі apt-getє двома прикладами. Якщо ви вводите вперед під час їх запуску, ви можете виявити, що перша частина вашого вводу зникла. Це може бути проблемою.

ssh remotehost do something that takes 20 seconds
mail bob
Dan has retired. Feel free to save any important files and then do
# ssh exits here, discarding the previous 2 lines
rm -fr *
.

Отже, після команди bash fork()s і execs, перша команда все ще приєднана до STDINоболонки bash? Здається, що відповідь «ні», bash, здається, буферизує наступну команду. Це правильно?
111 ---

Якщо ви не скажете оболонці перенаправляти stdin команди, команда матиме той самий stdin, що і оболонка. Все, що ви вводите, читається першим процесом, який його читає. Оболонка навмисно не намагається нічого прочитати, поки команда працює, і чекає, поки команда зупиниться. Речі стають складнішими, якщо поставити команду на задній план за допомогою &.
Марк Плотнік

Так STDINобробляється фіфо? І я гадаю, що, якщо дочірній процес bash явно не закриє успадковану ручку файлу, щоб STDINпотім він все ще міг прочитати з додаткового набору тексту?
111 ---

Так, всім термінальним входом обробляється FIFO. Не впевнений, що я розумію ваше друге запитання. Дочірній процес - команда, яку викликала оболонка - зазвичай не чітко закриває свій stdin; оболонка виходить із шляху і дозволяє команді читати все, що хоче, тоді дитина зупиняється і оболонка продовжує читати.
Марк Плотнік

Так, ви вирішили обидва мої подальші запитання дуже чітко, дякую!
111 ---

12

Основна поведінка, яку ви бачите, полягає в тому, що введення сидить у буфері десь до його зчитування (ну, якщо ви введете достатньо, з часом буфери заповняться, і щось загубиться, хоч було б багато вводити). Більшість речей, які виконуються через make, не читаються з STDIN, тому вона залишається в буфері.

Небезпека полягає в тому, що неправильна команда прочитає ваш вклад. Наприклад, makeназиває щось, що вирішує вас підказати, і тоді воно може прочитати вашу наступну команду як відповідь. Наскільки небезпечно це залежить, звичайно. (Вони також можуть спочатку промити весь вхід, лише відкинувши попередній вхід.)

Одна команда, яка зазвичай використовується в Makefiles, і це може зробити TeX. Якщо він зіткнеться з помилкою (і не надано прапор, щоб ніколи не спонукати користувача), він підкаже, як ви хочете продовжити.

Кращим варіантом є , ймовірно, бігти: make && make check.


8
  1. Ну, напів очевидно, ви не повинні виконувати другу команду, яка залежить від першої команди ( makeу вашому прикладі) успішно виконаної. Наприклад, це make foo Enter> ./foo Enter може призвести до проблеми. Ви можете спробувати увійти в звичку вводити такі речі, як make && make checkдруга команда буде виконуватися лише в тому випадку, коли перша успішна.
  2. Теоретично можливо, що перша команда (процес (и)) могла прочитати частину другої команди або інакше видалити її з буфера вхідного терміналу. Якби він з'їв перші шість символів make check, ви в кінцевому підсумку виконаєте команду heck, яка, ймовірно, не існує у вашій системі (але може бути щось неприємне). Якщо перша команда - це щось доброякісне, що ви знаєте і якому довіряєте, я не одразу бачу жодної проблеми.
  3. Як / чому це працює? Система буферизує вхід клавіатури. Це трохи схоже на електронну пошту: ви можете надіслати людині п'ять повідомлень за короткий проміжок часу, і вони будуть сидіти у його папці "Вхідні", чекаючи, коли він їх прочитає. Так само, доки перша команда не зчитується з клавіатури, команда (и), яку ви введете, буде сидіти і чекати, коли оболонка обійде їх для читання. Існує обмеження щодо кількості буферних перемог, але зазвичай це кілька сотень символів (якщо не кілька тисяч).

2
До точки 1, уявіть собі , що команди НЕ мають ніякого відношення, тобто lsі mount, наприклад. Я намагаюся зрозуміти, як обробляється буферний вхід. Дякую за відповідь.
111 ---
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.