В операционных системах Unix-подобных компьютеров конвейер — это механизм межпроцессного взаимодействия с использованием передачи сообщений. Конвейер — это набор процессов, связанных вместе их стандартными потоками , так что выходной текст каждого процесса ( stdout ) передается непосредственно в качестве ввода ( stdin ) следующему. Второй процесс запускается, пока первый процесс все еще выполняется, и они выполняются одновременно .
Концепция конвейеров была выдвинута Дугласом Макилроем в прародине Unix Bell Labs во время разработки Unix, сформировав его инструментальную философию . Она названа по аналогии с физическим конвейером . Ключевой особенностью этих конвейеров является их «сокрытие внутренностей». Это, в свою очередь, обеспечивает большую ясность и простоту в системе.
Каналы в конвейере являются анонимными каналами (в отличие от именованных каналов ), где данные, записанные одним процессом , буферизуются операционной системой до тех пор, пока они не будут прочитаны следующим процессом, и этот однонаправленный канал исчезает, когда процессы завершаются. Стандартный синтаксис оболочки для анонимных каналов — это перечисление нескольких команд, разделенных вертикальными чертами (« каналы » в общепринятой терминологии Unix).
Концепция конвейера была изобретена Дугласом Макилроем [1] и впервые описана в man-страницах версии 3 Unix . [2] [3] Макилрой заметил, что большую часть времени командные оболочки передавали выходной файл из одной программы в качестве входного в другую. Концепция конвейеров была выдвинута Дугласом Макилроем в прародине Unix Bell Labs во время разработки Unix, формируя его философию инструментария . [4] [5]
Его идеи были реализованы в 1973 году, когда («за одну лихорадочную ночь», как писал Макилрой) Кен Томпсон добавил pipe()
системный вызов и каналы в оболочку и несколько утилит в версии 3 Unix. «На следующий день», продолжил Макилрой, «увидел незабываемую оргию однострочников, когда все присоединились к восторгу сантехники». Макилрой также приписывает Томпсону нотацию |
, которая значительно упростила описание синтаксиса каналов в версии 4. [ 6] [2]
Хотя каналы Unix были разработаны независимо, они связаны с «файлами связи», разработанными Кеном Лохнером [7] в 1960-х годах для системы разделения времени Дартмута , и им предшествовали . [8]
Эта функция Unix была заимствована другими операционными системами, такими как MS-DOS и пакет CMS Pipelines в VM/CMS и MVS , и в конечном итоге получила название шаблона проектирования каналов и фильтров в программной инженерии .
В коммуникационных последовательных процессах (CSP) Тони Хоара трубы Макилроя получили дальнейшее развитие. [9]
Механизм конвейера используется для межпроцессного взаимодействия с использованием передачи сообщений. Конвейер — это набор процессов, связанных вместе их стандартными потоками , так что выходной текст каждого процесса ( stdout ) передается непосредственно в качестве ввода ( stdin ) следующему. Второй процесс запускается, когда первый процесс все еще выполняется, и они выполняются одновременно . Он назван по аналогии с физическим конвейером . Ключевой особенностью этих конвейеров является их «сокрытие внутренностей». [10] Это, в свою очередь, обеспечивает большую ясность и простоту в системе.
В большинстве Unix-подобных систем все процессы конвейера запускаются одновременно, их потоки соответствующим образом подключены и управляются планировщиком вместе со всеми другими процессами, запущенными на машине. Важным аспектом этого, отличающим конвейеры Unix от других реализаций конвейеров, является концепция буферизации : например, отправляющая программа может производить 5000 байт в секунду , а принимающая программа может принимать только 100 байт в секунду, но данные не теряются. Вместо этого вывод отправляющей программы удерживается в буфере. Когда принимающая программа готова к чтению данных, следующая программа в конвейере считывает данные из буфера. Если буфер заполнен, отправляющая программа останавливается (блокируется) до тех пор, пока по крайней мере некоторые данные не будут удалены из буфера получателем. В Linux размер буфера составляет 65 536 байт (64 КБ). Доступен сторонний фильтр с открытым исходным кодом, называемый bfr, для предоставления больших буферов, если это необходимо.
Такие инструменты, как netcat и socat, могут подключать каналы к сокетам TCP/IP .
Все широко используемые оболочки Unix имеют специальную синтаксическую конструкцию для создания конвейеров. Во всех случаях команды пишутся последовательно, разделяясь символом вертикальной черты ASCII (который по этой причине часто называют «символом конвейера»). Оболочка запускает процессы и организует необходимые соединения между их стандартными потоками (включая некоторое количество буферного хранилища).|
Конвейер использует анонимные каналы . Для анонимных каналов данные, записанные одним процессом, буферизуются операционной системой до тех пор, пока они не будут прочитаны следующим процессом, и этот однонаправленный канал исчезает, когда процессы завершаются; это отличается от именованных каналов , где сообщения передаются в или из канала, который назван путем создания файла, и остается после завершения процессов. Стандартный синтаксис оболочки для анонимных каналов заключается в перечислении нескольких команд, разделенных вертикальными чертами («каналами» в общепринятой терминологии Unix):
команда1 | команда2 | команда3
Например, чтобы вывести список файлов в текущем каталоге ( ls ), сохранить только строки вывода ls , содержащие строку «key» ( grep ), и просмотреть результат на прокручиваемой странице ( less ), пользователь вводит в командную строку терминала следующее:
ls -l | grep key | меньше
Команда ls -l
выполняется как процесс, вывод (stdout) которого направляется на ввод (stdin) процесса для grep key
; и аналогично для процесса для less
. Каждый процесс принимает ввод от предыдущего процесса и создает вывод для следующего процесса через стандартные потоки . Каждый |
сообщает оболочке о необходимости соединить стандартный вывод команды слева со стандартным вводом команды справа с помощью механизма межпроцессного взаимодействия, называемого (анонимным) каналом , реализованного в операционной системе. Каналы являются однонаправленными; данные проходят по конвейеру слева направо.
Ниже приведен пример конвейера, реализующего своего рода проверку орфографии для веб- ресурса, указанного URL . Далее следует объяснение того, что он делает.
curl "https://en.wikipedia.org/wiki/Pipeline_(Unix)/Pipeline_(Unix)" | sed 's/[^a-zA-Z ]/ /g' | тр 'AZ ' 'az\n' | grep '[az]' | сортировка -u | комм -23 - < ( сортировка /usr/share/dict/words ) | меньше
curl
получает HTML- содержимое веб-страницы (может использоваться wget
в некоторых системах).sed
заменяет все символы (из содержимого веб-страницы), которые не являются пробелами или буквами, пробелами. ( Переходы на новую строку сохраняются.)tr
заменяет все заглавные буквы на строчные и преобразует пробелы в строках текста в символы новой строки (каждое «слово» теперь находится на отдельной строке).grep
включает только строки, содержащие хотя бы одну строчную букву алфавита (без пустых строк).sort
сортирует список «слов» в алфавитном порядке, а -u
переключатель удаляет дубликаты.comm
находит общие строки в двух файлах, -23
подавляет строки, уникальные для второго файла, и те, которые являются общими для обоих, оставляя только те, которые найдены только в первом названном файле. -
Вместо имени файла comm
используется его стандартный ввод (в данном случае из конвейера). sort /usr/share/dict/words
сортирует содержимое words
файла в алфавитном порядке, как и comm
ожидается, и <( ... )
выводит результаты во временный файл (через подстановку процесса ), который comm
читает. Результатом является список слов (строк), которые не найдены в /usr/share/dict/words.less
позволяет пользователю пролистывать результаты.По умолчанию стандартные потоки ошибок (" stderr ") процессов в конвейере не передаются через конвейер; вместо этого они объединяются и направляются в консоль . Однако во многих оболочках есть дополнительный синтаксис для изменения этого поведения. Например, в оболочке csh|&
использование вместо |
означает, что стандартный поток ошибок также должен быть объединен со стандартным выводом и передан следующему процессу. Оболочка Bash также может объединять стандартные ошибки с , |&
начиная с версии 4.0 [11] или с помощью 2>&1
, а также перенаправлять его в другой файл.
В наиболее часто используемых простых конвейерах оболочка соединяет ряд подпроцессов через каналы и выполняет внешние команды внутри каждого подпроцесса. Таким образом, сама оболочка не выполняет прямую обработку данных, проходящих через конвейер.
Однако оболочка может выполнять обработку напрямую, используя так называемую мельницу или конвейерную мельницу (поскольку while
команда используется для «перемалывания» результатов исходной команды). Эта конструкция обычно выглядит примерно так:
команда | while read -r var1 var2 ... ; do # обработать каждую строку, используя переменные, преобразованные в var1, var2 и т. д. # (обратите внимание, что это может быть подоболочка: var1, var2 и т. д. будут недоступны # после завершения цикла while; некоторые оболочки, такие как zsh и более новые # версии оболочки Korn, обрабатывают команды слева от оператора pipe # в подоболочке) done
Такой конвейер может не работать так, как задумано, если тело цикла включает команды, такие как cat
и ssh
, которые считывают из stdin
: [12] на первой итерации цикла такая программа (назовем ее стоком ) считывает оставшийся вывод из command
, а затем цикл завершается (с результатами, зависящими от специфики стока). Есть несколько возможных способов избежать такого поведения. Во-первых, некоторые стоки поддерживают опцию отключения чтения из stdin
(например ssh -n
). В качестве альтернативы, если стоку не нужно считывать какие-либо входные данные из stdin
для выполнения чего-либо полезного, их можно задать < /dev/null
в качестве входных данных.
Поскольку все компоненты конвейера выполняются параллельно, оболочка обычно разветвляет подпроцесс (подоболочку) для обработки его содержимого, что делает невозможным распространение изменений переменных во внешнюю среду оболочки. Чтобы исправить эту проблему, «pipemill» может быть вместо этого загружен из документа here, содержащего подстановку команды , которая ждет завершения работы конвейера перед проработкой содержимого. В качестве альтернативы для параллельного выполнения можно использовать именованный конвейер или подстановку процесса . GNU bash также имеет lastpipe
возможность отключить разветвление для последнего компонента конвейера. [13]
pipe()
Конвейеры могут быть созданы под управлением программы. Системный вызов Unix просит операционную систему создать новый анонимный объект конвейера. Это приводит к появлению двух новых открытых файловых дескрипторов в процессе: конца конвейера, доступного только для чтения, и конца, доступного только для записи. Концы конвейера выглядят как обычные анонимные файловые дескрипторы , за исключением того, что они не имеют возможности поиска.
Чтобы избежать взаимоблокировки и использовать параллелизм, процесс Unix с одним или несколькими новыми каналами затем, как правило, вызывает fork()
создание новых процессов. Затем каждый процесс закрывает конец(и) канала, которые он не будет использовать, перед тем как производить или потреблять какие-либо данные. В качестве альтернативы, процесс может создавать новые потоки и использовать канал для связи между ними.
Именованные каналы также могут быть созданы с использованиемmkfifo()
илиmknod()
и затем представлены как входной или выходной файл для программ по мере их вызова. Они позволяют создавать многопутевые каналы и особенно эффективны в сочетании со стандартным перенаправлением ошибок или сtee
.
Робот на иконке Automator от Apple , который также использует концепцию конвейера для объединения повторяющихся команд в цепочку, держит трубу в знак уважения к оригинальной концепции Unix.
Макилрой: Это было одно из немногих мест, где я почти осуществлял управленческий контроль над Unix, продвигал эти вещи, да.
{{cite web}}
: CS1 maint: числовые имена: список авторов ( ссылка )