Loading AI tools
З Вікіпедії, вільної енциклопедії
В Unix-подібних операційних системах конвеєр — це механізм міжпроцесної взаємодії, що використовує передачу повідомлень. Є набором поєднаних між собою процесів, які забезпечують передачу даних так, що стандартний вихідний потік кожного процесу (stdout) безпосередньо з'єднується зі стандартним вхідним потоком (stdin) наступного. Наступний процес починається, поки перший ще виконується і вони виконуються одночасно. Концепцію було запропоновано Дугласом Макілроєм в Bell Labs, колисці Unix, в процесі його розробки та формування філософії інструментизації[1][2]. Назву дано за аналогією зі справжніми конвеєрами. Ключовою функцією цих конвеєрів є «приховування нутрощів» (Ritchie & Thompson, 1974). Це забезпечує системі чистоту за простоту.
У цій статті йдеться про неіменовані канали, де дані, повернені одним процесом, буферизуються системою, поки не будуть зчитані наступним процесом і цей односпрямований канал зникає з закінченням процесів. Це відрізняється від іменованих каналів, де повідомлення передаються між процесами файлами, які залишаються по закінченні процесів. Стандартний shell-синтаксис для неіменованих каналів — це список декількох команд, розділених вертикальними рисками («пайпи» в розмовній лексиці користувачів Unix):
command1 | command2 | command3
Наприклад, щоб отримати список файлів в поточній директорії, зберегти лише стрічку ls виводу, що має рядок "key" (grep) і показати результат на сторінці, що прогортується (less), користувач може написати в командний рядок терміналу наступне:
ls -l | grep key | less
Командаls -l
виконується як процес, вивід (stdout) якого передається вводу (stdin) процесу команди grep key
, так само з командою less
. Кожен процес приймає ввід від попереднього і передає свій вивід наступному стандартними потоками. Кожен |
вказує командній оболонці під'єднати стандартний вивід команди зліва до стандартного вводу команди справа через механізм взаємодії між процесами, що називають неіменованим каналом, вбудованим в операційну систему. Канали є односторонніми: дані переходять каналом лише зліва направо.
Нижче наведений приклад конвеєра, що реалізовує перевірку орфографії для веб-сторінки, на яку вказує посилання.
curl "https://en.wikipedia.org/wiki/Pipeline_(Unix)" |
sed 's/[^a-zA-Z ]/ /g' |
tr 'A-Z ' 'a-z\n' |
grep '[a-z]' |
sort -u |
comm -23 - <(sort /usr/share/dict/words) |
less
curl
отримує html вміст вебсторінки (для деяких систем використовують wget
).sed
замінює всі символи (з вмісту вебсторінки), що не є пробілами чи літерами, на пробіли (зі збереженням переходу на новий рядок)tr
змінює всі великі літери на малі і конвертує пробіли у переходи на новий рядок (кожне «слово» тепер в окремому рядку).grep
приймає лише ті рядки, які містять щонайменше одну малу літеру алфавіту, таким чином виключаючи пусті рядки.sort
сортує список «слів» в алфавітному порядку, а -u
видаляє дублікати.comm
шукає стрічки, що є однаковими в обидвох файлах, -23
виключає вивід стрічок, що є унікальними в другому файлі та однаковими в обох файлах, виводячи лише стрічки, унікальні для першого файлу. -
на місці назви файлу вказує процесу comm
використовувати стандартний потік вводу (в даному випадку з конвеєра). sort /usr/share/dict/words
сортує вміст файлу words
за алфавітом (за вимогами процесу comm
). <( ... )
виводить результат виконання в тимчасовий файл (використовуючи процесне заміщення), який зчитує comm
. Результатом є список слів (стрічок), не знайдених в /usr/share/dict/words
less
дозволяє користувачеві розділити результат на сторінки і прогортувати їх.Всі широко використовувані оболонки Unix мають власний синтаксис для створення конвеєрів. Загалом, команди пишуть послідовно, розділюючи їх вертикальною рискою ASCII |
(яку з цієї ж причини часто називають «пайпом»). Командна оболонка розпочинає процеси і організовує необхідні зв'язки між їхніми стандартними потоками, використовуючи деякий обсяг буферу.
За замовчуванням стандартні потоки виводу помилок («stderr») процесів в конвеєрі не передаються далі, натомість з'єднуються і направляються в консоль. Однак, багато оболонок мають додатковий синтаксис для зміни цих налаштувань. Наприклад, використання |&
замість |
в оболонці csh означає, що стандартний потік виводу помилок теж треба злити зі стандартним виводом і передати наступному процесу.
У найпростіших та найпоширеніших конвеєрах, оболонка з'єднує серію підпроцесів каналами і виконує зовнішні команди безпосередньо в підпроцесі. Таким чином сама оболонка не виконує прямої обробки даних, що передаються каналом.
Однак, оболонка може напряму обробляти дані, використовуючи так звані канальні роздрібнювачі (оскільки команда while
«роздібнює» результати з початкової команди і проходиться по кожному з них). Загальний вигляд такого конструкту виглядає наступним чином:
command | while read -r var1 var2 ...; do
# process each line, using variables as parsed into var1, var2, etc
# (note that this may be a subshell: var1, var2 etc will not be available
# after the while loop terminates; some shells, such as zsh and newer
# versions of Korn shell, process the commands to the left of the pipe
# operator in a subshell)
done
Такі конструкти можуть виконуватись некоректно, якщо тіло циклу містить такі команди, як cat
i ssh
, які потребують зчитування з stdin
:[3] при першій його ітерації. Така програма (назвімо її стоком) зчитуватиме залишковий вивід з command
і цикл буде припинено (його результат залежатиме від специфіки стоку). Є декілька шляхів уникнення такого сценарію. По-перше, деякі стоки підтримують можливість вимкнення читання з stdin
(напр. ssh -n
). Як альтернатива, якщо стік не потребує вхідних даних з stdin
, щоб зробити щось корисне, вхідними даними може бути < /dev/null.
Оскільки всі складові каналу виконуються паралельно, оболонка типово розділяє підпроцес (підоболонку), щоб обробити його вміст, що унеможливлює поширення зміни змінної в зовнішню оболонку. Щоб виправити цю проблему, даний конструкт може прийняти значення з here-документу, що містить командне заміщення, яке очікує завершення конвеєру, перш ніж проходитись по даних. В альтернативу цьому, для розпаралелення можна використовувати іменовані канали або заміщення процесів. GNU bash також має варіант lastpipe
для вимкнення розділення останнього компоненту каналу.[4]
Конвеєри можуть бути створені програмно. Системний виклик в Unix pipe()
просить операційну систему побудувати новий об'єкт неіменованого каналу. Результатом є відкриті два нові файлові дескриптори процесу: один лише для читання, другий лише для запису. Вони схожі зі звичайними неіменованими файловими дескрипторами, але в них немає можливості пошуку.
Щоб уникнути взаємного блокування та використати розпаралелення, Unix процес з одним або більше новим каналом викликає fork()
, щоб створити нові процеси.
Іменовані канали теж можна створити командою mkfifo()
або mknod[en]()
.
В більшості Unix-подібних системах всі процеси конвеєра починаються одночасно. Їхні потоки повинні бути відповідно правильно під'єднані і організовані планувальником разом з іншими процесами, що виконуються машиною. Важливим аспектом цього є наступне: відділяти Unix канали від інших каналів, що виконуються, є концептом буферингу. Наприклад, програма-відправник може генерувати 5000 байтів на секунду, а програма-отримувач може отримувати лише 100 байтів на секунду, але при цьому дані не втрачаються, а зберігаються в буфері. Коли отримувач готовий приймати дані, наступний процес конвеєру зчитує їх з буферу. Якщо він заповнений, програма-відправник блокується, поки певний об'єм даних не переміститься з буферу до отримувача. В Лінуксі розмір буферу складає 65546 байтів (64КБ). У відкритих джерелах можна знайти сторонній фільтр bfr для забезпечення буферу більшого об'єму при потребі.
Дуглас Макілрой[5] винайшов концепт конвеєру і вперше описав його в посібнику для Version 3 Unix[6]. Макілрой помітив, що дуже часто командні оболонки передавали вихідні дані однієї програми на вхід іншій.
Його ідеї були втілені в 1973 році, коли Кен Томпсон додав системний виклик pipe()
і канали до оболонки і декількох утиліт Version 3 Unix. Позначення |
— також заслуга Томпсона, це значно полегшило опис синтаксису у Version 4.[7][6]
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.