Как работает pipe в командах bash?

Как работает pipe в командах bash?

Происходит ли что-нибудь символическое при объединении команд 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
         └───────────┘ └───────────┘ └─────────────┘

Связанный контент