
Происходит ли что-нибудь символическое при объединении команд bash через конвейер или все происходит по принципу «вычислить-передать-вычислить-передать»?
Например head t.txt -n 5 | tail -n 2
, в , head t.txt -n 5
вычисляется и затем tail -n 2
выполняется над ним. Или сначала есть некая абстракция, сообщающая оболочке, что строки с 3 по 5 должны быть прочитаны? Это может не иметь значения в этом примере, но я думаю, может в других сценариях.
решение1
Оболочка использует pipe(2)
системный вызов для создания ограниченного буфера в ядре с двумя файловыми дескрипторами: один для разрешения процессам записывать данные в буфер, а другой для разрешения процессам читать данные из буфера.
Рассмотрим простой случай:
$ p1 | p2
В этом случае, концептуально, оболочка создает вышеупомянутый канал, fork()
s, потомок подключает свой стандартный поток вывода к концу записи канала, затем потомок exec()
s p1
. Затем, снова оболочка fork()
s, потомок подключает свой стандартный поток ввода к концу чтения канала, затем потомок exec()
s p2
. (Я говорюконцептуально(Поскольку оболочки могут выполнять действия в разном порядке, но идея та же самая.)
В этот момент p1
и p2
работают одновременно. p1
будет писать в канал, а ядро будет копировать записанные данные в буфер. p2
будет читать из канала, а ядро будет копировать считанные данные из буфера. Если канал заполняется, то ядро заблокирует p1
свой вызов, write()
пока не p2
прочитает что-то из канала, освободив немного места. Если канал пуст, то ядро заблокирует p2
свой вызов, read()
пока не p1
запишет больше данных в канал.
решение2
Из двух предложенных вами моделей compute-pass-compute-pass наиболее близка. Оболочка просто соединяет процессы. Она ничего не знает о том, что они делают.
Кроме, Порядок выполнения не определен. Они фактически работают одновременно. Однако тот, что слева, должен вывести байты до того, как тот, что справа, их введет. Данные идут слева направо. Данные идут от первой команды, выходят из ее стандартного вывода, затем поступают в стандартный ввод следующего процесса, где они обрабатываются, затем выходят из его стандартного вывода, откуда их можно передать другому процессу и т. д., и т. п., и т. п.
Если нет перенаправления >
, <
и т.п. или чтения из файла. Тогда это выглядит так.
┌───────────┐ ┌───────────┐ ┌─────────────┐
Terminal⇨│Process one│⇨│Process two│⇨│Process Three│⇨Terminal
└───────────┘ └───────────┘ └─────────────┘