Pipes Програмні канали в Linux

Зміст

Передмова

В одній дотепній статті я прочитав наступну сентенцію: "Позбавити прихильника Юнікс програмних каналів - те саме, що відібрати мишу у користувача Віндоуз". Можливо, в цьому твердженні і є деяке перебільшення, але за старих часів так воно, за великим рахунком, і було. Досвідчені прихильники Юніксоподібних систем люблять консоль і вміють нею користуватися. Ми ж, нинішні, встановивши Убунту, вже вважаємо себе лінуксоїдами, а що таке консоль, маємо невиразне уявлення. Але минає деякий час, і, втомившись від прикраси робочого столу, прочитавши дві-три статейки, ми наважуємося натиснути мишкою на значок монітора в системному треї. Згодом перед нами відкривається новий світ, сповнений дивовижних можливостей і безперервного вдосконалення своїх знань, світ бенкету інтелекту, безперервного експерименту, і радості від того, що ти Homo Sapiens. Девіз: "Повернемо радість у спілкування з комп'ютером!", - якнайкраще підходить для цього випадку.

Вибір терміну

Термін pipe (труба) надзвичайно органічно увійшов до англомовного комп'ютерного жаргону. Цим словом називається як спосіб передачі виведення однієї команди на введення інший, а й оператор, яким позначається це: (вертикальна характеристика). Крім того, те саме слово є дієсловом, що означає дану дію.

Які тільки терміни не використовують українською мовою для перекладу слова "pipes": і труби, і трубопроводи, і конвеєри, і потоки, та інше. У тих ці терміни виглядають досить незграбно. І ось ще біда - від жодного з цих іменників не можна утворити дієслово, не кажучи вже про те, щоб називати так символ вертикальної риси. Можна, щоправда, вжити дієслово "конвеєризувати", але таке ненаписати, не вимовити неможливо. Я намагався робити позначки цієї статті, використовуючи всі перераховані терміни, але не був задоволений жодним.

Цілком випадково, в книзі А. Робачівського "Операційна система UNIX" мені зустрівся термін "програмні канали". Спочатку він здався мені дещо громіздким, але спробувавши його на ділі, я переконався у його безперечних перевагах. Він не виглядає смішно і дико як "труби", від нього легко зробити дієслово, і, найголовніше, він має брата, що цілком прижився на українському ґрунті, - "іменовані канали", які ніхто не назве "іменованими трубопроводами". Отже, вирішено, у цій статті термін "pipes" звучатиме як "програмні канали".

Введення у програмні канали

Програмним каналом називається використання виведення однієї команди як введення для іншої програми. Наприклад:

Команда dmesg виводить повідомлення ядра Лінукс про процес завантаження ОС (те самі, що пробігають екраном монітора під час завантаження системи). Ці повідомлення не вміщаються на одному екрані, і пролітають так швидко, що їх неможливо прочитати. Тому виведення програми dmesg передають введення команді less. (Команда less дозволяє виводу команди dmesg заповнити лише один екран. Щоб прочитати наступну порцію тексту, потрібно натиснути клавішу пробілу, а щоб повернутися до попередньої порції – клавішу b. Перервати роботу програми можна клавішею q). Оператором такої передачі є вертикальна характеристика (). (Пробіли до і після вертикальної межі ставляться для зручності читання, але можна обійтися і без них). Все разом і є найпростішим програмним каналом.

Очевидно, що така схема менш продуктивна: по-перше, необхідно давати дві команди, по-друге, тому що наступна команда може почати працювати тільки після завершення першої.

Необхідно пояснити поняття, які я походя назвав "введенням" та "висновком" програми.

Будь-яка програма командної оболонки (шелла) оперує з трьома потоками даних: стандартним введенням (stdin), стандартним виведенням (stdout) і стандартним повідомленням про помилку (stderr). (Докладно про це можна прочитати у статті "Перенаправлення стандартних потоків даних").

За замовчуванням, стандартне введення здійснюється з клавіатури, а стандартне виведення - на екран монітора. Якщо ж ми задіємо оператор програмних каналів (), то стандартне виведення першої програми стане стандартним введенням другої, при цьому на екрані монітора він вже не з'явиться.

Такий ланцюжок зовсім не обмежується двома програмами, але може продовжуватися як завгодно довго.

Як це працює

У більшості Юніксоподібних систем всі процеси в програмному каналі починаються одночасно, їх потоки відповідно з'єднуються і управляються планувальником разом з усіма іншими процесами, що йдуть у системі.

Навіть якщо програма, що посилає, виробляє 5000 байт в секунду, а приймаюча програма може обробити тільки 100 байт в секунду, все одно ніякої втрати інформації не відбудеться, так як програмні канали мають буфери. Висновок програми, що посилає, збирається в буфері, ставиться в чергу. Коли програма, що приймає, готова зчитувати дані, операційна система посилає порцію даних з буфера. У разі переповнення буфера, програма, що посилає, зупиняється (блокується), доки приймаюча програма не зможе знову зчитувати дані, тим самим звільняючи буфер.

Механізм цієї властивості командної оболонки досить складний, у цій статті ми не будемо його розглядати, а просто користуватися цією чудовою здатністю шелла.

Яккористуватися програмними каналами

Найчастіше використовуються програмні канали, які закінчуються командами less і більше. Ці дві команди схожі на свою дію, однак less новіший і має ряд додаткових функцій, включаючи можливість повернутися до попередніх "сторінок" виведення. Багато хто користується цими програмними каналами, не підозрюючи, що займаються настільки складними речами.

Крім наведеного вище прикладу з каналом dmesg less, часто використовується канал ls less. Команда ls дозволяє переглядати вміст директорій, а з опцією -l дає докладні відомості про файли, що "населяють" зазначену директорію. Якщо директорія містить достатньо файлів, щоб їх список зайняв більше одного екрану, то застосування програмного каналу з less або більше неминуче:

Для проби зробіть такий приклад:

Зрозуміло, що знайти вручну щось у такому списку проблематично, і тут на допомогу знову прийдуть програмні канали.

Команда grep знайде потрібні вам рядки, якщо ви поставите зразок для пошуку:

Зверніть увагу на символ # на початку командного рядка - він означає, що я увійшов із правами суперкористувача.

Команди, що входять до складу програмних каналів, часто називаються командами-фільтрами, оскільки вони пропускають через себе потоки даних.

Це лише початок списку рядків, виведених командою grep -i usb, я не наводжу його повністю з економії місця. Опція -i наказує команді grep не помічати різниці між великими та малими літерами.

Будь-який системний адміністратор часто користується командою ps. З опціями -e і -f вона виводить усі процеси, які у системі у повній формі (докладно). Процесів цих дуже багато, тому я не наводжу повного висновку команди:

Щоб знайти в цьому списку цікаві для вас процеси, слідканалізувати команду ps із командою grep. Допустимо, вас цікавлять процеси hald:

З таким коротким списком легше працювати. (Зверніть увагу на останній рядок, там представлений сам запущений нами процес grep hald).

Інші поширені команди-фільтри

Окрім команди grep (або разом з нею) часто використовуються такі команди:

У цей список я включив лише кілька команд-фільтрів, освоївши які, можна вдосталь насолодитися складанням найпростіших програмних каналів.

Складні програмні канали

Ось приклад, як налагодити перевірку орфографії за допомогою програмних каналів. Припустимо, що у вас є файл words.txt, в якому містяться всі слова англійської мови (зрозуміло, такого файлу у вас немає, але можна запозичити список слів з якогось словника; а англійської - щоб не плутатися з кодуванням). Тоді складається наступний програмний канал:

Примітка:Символ (\) використовується для об'єднання всіх шести рядків в один командний рядок.

Команда перша: wget отримує вміст HTML-сторінки.

Команда друга: sed видаляє з тексту сторінки всі символи, що не є пробілами або літерами та замінює їх пробілами.

Команда третя: tr переводить усі символи верхнього регістру в нижній регістр (великі літери в малі), а також конвертує пробіли в рядках у символи нового рядка, так що тепер кожне "слово" є новим рядком.

Команда четверта: grep залишає лише рядки, що містять хоча б один алфавітний символ (просто букву), видаляючи всі порожні рядки.

Команда п'ята: sort сортує список "слів" за абеткою, а з опцією -u видаляє дублікати.

Команда шоста, та остання: comm знаходить рядки, загальні для двохфайлів. Першим файлом є стандартний висновок нашого програмного каналу, навіщо замість імені першого файлу стоїть прочерк (-), другим файлом буде файл words.txt. Рядки, які зустрічаються лише у другому файлі та ті, що зустрічаються в обох файлах, пригнічуються опціями -2 та -3. Результатом буде список слів, що зустрічаються лише у першому файлі. І, якщо вважати файл words.txt якимось еталонним словником, то список, що виходить, буде містити слова, яких немає в словнику, тобто написані з помилками.

Трохи історії

Поняття іменованого каналу

Англійська назва іменованого каналу – named pipe або FIFO (File In, File Out – файл прийшов, файл пішов). Іменовані канали служать в основному для міжпроцесної взаємодії, коли різні процеси в системі обмінюються інформацією. Тема це складна і велика, яка заслуговує на окрему статтю. Тому в цій роботі я тільки коротко торкнуся її.

На відміну від анонімного програмного каналу, що автоматично створюється шеллом, іменований канал має ім'я, і ​​створюється явно за допомогою команд mknod або mkfifo. Створимо іменований канал fifo1:

Тепер запустимо процес, що звертається до цього каналу:

Незважаючи на натискання клавіші ENTER нічого не відбувається, що не дивно, адже файл fifo1 поки порожній, і команді grep нема чого обробляти. Однак консоль виявляється зайнята процесом, що чекає, і розблокувати її можна тільки перервавши процес (скажімо, натисканням клавіш CTRL+c).

Щоб наповнити іменний канал вмістом, потрібно, щоб до нього звернувся другий процес. Для цього ми повинні відкрити другу консоль і запустити будь-яку команду, яка передає дані файлу fifo1. Наприклад:

Негайно у першій консолі спрацює команда grep:

Цілком зрозуміло, що користуватисятаким незручним механізмом в цілях користувача ніхто не буде, адже набагато простіше запустити один програмний канал:

і отримати той самий результат.

Цей приклад я навів лише для демонстрації створення та роботи іменованого каналу. Інша річ, коли іменовані канали створюються самими процесами обмінюватись інформацією друг з одним. Але повторюся, що ця тема непроста і в цій статті розглядатися не буде.

Програмні канали - найпотужніший інструмент Юніксоподібних операційних систем. Створення програмних каналів багаторазово прискорює процес обробки даних, скорочує кількість "писанини" у командному рядку, а також дозволяє отримувати результат у найбільш зручному вигляді.