Безопасно ли вводить другую команду в STDIN, когда предыдущая команда записывает в STDOUT?

21

Возможно, на это уже отвечали ранее, я бы приветствовал ссылку на другой ответ ...

Если я выполню команду оболочки (в bashоболочке), как показано ниже:

make

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

Мой вопрос (ы) просто:

  1. Это опасно делать?
  2. Есть ли какие-либо потенциальные неожиданные поведения от этого вида арифметики?
  3. Почему это работает так, как работает?
111 ---
источник
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обрабатывается ли в фаворской манере? И я полагаю, что если дочерний процесс bash явно не закроет свой унаследованный дескриптор файла, STDINто он все равно сможет читать из дополнительной типизации?
111 ---
Да, все входные данные терминала обрабатываются FIFO. Не уверен, что понимаю ваш второй вопрос. Дочерний процесс - команда оболочки применит - обычно делает не явно близко его стандартный ввод; оболочка выходит из пути и позволяет команде читать все, что она хочет, затем дочерний процесс останавливается и оболочка возобновляет чтение.
Марк Плотник
Да, вы очень четко ответили на оба моих последующих вопроса, спасибо!
111 ---
12

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

Опасность заключается в том, что неправильная команда читает ваш ввод. Например, makeвызывает что-то, что решит подсказать вам, а затем может прочитать вашу следующую команду в качестве ответа. Насколько это опасно, конечно, зависит от команды. (Они также могут сначала сбрасывать все входные данные, просто отбрасывая ваш предыдущий ввод.)

Одна из команд, обычно используемая в Makefiles, это может быть TeX. Если он обнаружит ошибку (и ему не будет дан флажок, чтобы он никогда не предлагал пользователю), он подскажет, как вы хотите продолжить.

Лучшим вариантом является , вероятно, бежать: make && make check.

derobert
источник
8
  1. Ну, очевидно, вы не должны запускать вторую команду, которая зависит от того, была ли первая команда ( makeв вашем примере) выполнена успешно. Например, make foo Enter> ./foo Enter может вызвать проблему. Возможно, вы захотите попробовать набрать такие вещи, как make && make check, например , когда вторая команда будет выполнена только в случае успеха первой.
  2. Теоретически возможно, что первая команда (процесс (ы)) могла бы прочитать часть второй команды или иным образом удалить ее из буфера ввода терминала. Если бы он употреблял первые шесть символов make check, вы бы в итоге выполнили команду heck, которая, вероятно, не существует в вашей системе (но может быть чем-то неприятным). Если первая команда - это что-то доброе, что вы знаете и которому доверяете, я не вижу никаких проблем.
  3. Как / почему это работает? Система буферизует ввод с клавиатуры. Это немного похоже на электронную почту: вы можете отправить человеку пять сообщений за короткий промежуток времени, и они будут сидеть в его папке «Входящие», ожидая, пока он их прочитает. Точно так же, пока первая команда не читает с клавиатуры, набираемая вами команда будет сидеть и ждать, пока оболочка приступит к их чтению. Существует ограничение на количество буферизируемых «впереди», но обычно это несколько сотен символов (если не несколько тысяч).
Скотт
источник
2
К точке 1, представьте себе , что команды не имеют никакого отношения, то есть lsи mount, например. Я пытаюсь понять, как обрабатывается буферный ввод. Спасибо за ответ.
111 ---