Канали та фільтри
Останнє оновлення 2025-09-04 | Редагувати цю сторінку
Огляд
Питання
- Як я можу комбінувати команди, що вже існують, щоб робити нові речі?
 - Як відобразити лише частину виведених даних?
 
Цілі
- Зрозуміти перевагу поєднання команд за допомогою каналів та фільтрів.
 - Навчитись комбінувати послідовності команд для отримання нового результату
 - Навчитись перенаправляти вивід команди до файлу.
 - Зрозуміти, що зазвичай відбувається, якщо програмі або конвеєру не надається жодних вхідних даних для обробки.
 
Тепер, після ознайомлення з основними командами, ми можемо нарешті
розглянути найпотужнішу функцію терміналу: здатність комбінувати наявні
програми різними способами. Ми почнемо з каталогу
shell-lesson-data/exercise-data/proteins, який містить
шість файлів, що описують деякі прості органічні молекули. Розширення
.pdb вказує на те, що ці файли мають формат Protein Data
Bank - простий текстовий формат, який визначає тип і положення кожного
атома в молекулі.
ВИХІД
cubane.pdb    methane.pdb    pentane.pdb
ethane.pdb    octane.pdb     propane.pdb
Запустимо наприклад цю команду:
ВИХІД
20 156 1158 cubane.pdb
wc - команда для підрахунку слів (англ. ‘word count’):
вона рахує кількість рядків, слів і символів у файлах (повертаючи
значення в такому порядку зліва направо).
Якщо ми виконаємо команду wc *.pdb, то символ
* у *.pdb відповідає будь-якій кількості
символів (включаючи пустий рядок), тож термінал перетворить
*.pdb на перелік усіх файлів з розширенням
.pdb у поточному каталозі:
ВИХІД
  20  156  1158  cubane.pdb
  12  84   622   ethane.pdb
   9  57   422   methane.pdb
  30  246  1828  octane.pdb
  21  165  1226  pentane.pdb
  15  111  825   propane.pdb
 107  819  6081  total
Зверніть увагу, що wc *.pdb в останньому рядку свого
виводу також показує загальну кількість усіх рядків у перелічених
файлах.
Якщо ми виконаємо wc -l замість просто wc,
то виводитиметься лише кількість рядків у файлах:
ВИХІД
  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total
Параметри -m та -w з командою
wc дозволяють показувати тільки кількість символів або
тільки кількість слів у файлах.
Чому нічого не відбувається?
Що станеться, коли команді, яка має обробляти файл, не надати його назву? Наприклад, що буде, якщо ми наберемо:
але не будемо вводити *.pdb (або щось інше) після цієї
команди? Оскільки команда не отримала жодних назв файлів,
wc вважає, що треба обробляти введені дані з командного
рядка, тому вона просто очікує, поки ми надамо їй якісь дані
інтерактивно. Ззовні, однак, це виглядає так, ніби команда нічого не
робить.
Якщо ви припустилися такої помилки, ви можете вийти з цього стану, утримуючи клавішу control (Ctrl), та один раз натиснувши клавішу C: Ctrl+C. Потім відпустіть обидві клавіші.
Перехоплення виводу з команд
Який з цих файлів містить найменшу кількість рядків? Це легко визначити, коли файлів лише шість, але що робити, якщо їх 6000? Наш перший крок до пошуку рішення - це запуск наступної команди:
Символ ‘більше ніж’, тобто >, вказує терміналу
перенаправити вивід команди до файлу замість виведення
його на екран. Ця команда не виводить дані на екран, оскільки увесь
вивід wc записується до файлу lengths.txt.
Якщо файлу не існувало до виконання команди, його буде створено. Якщо
файл вже існує, він буде непомітно перезаписаний, що може призвести до
втрати даних. Таким чином, перенаправлення команд
вимагає обережності.
Команда ls lengths.txt підтверджує, що файл існує:
ВИХІД
lengths.txt
Тепер ми можемо вивести вміст файлу lengths.txt на екран
за допомогою команди cat lengths.txt. Назва команди
cat походить від слова ‘concatenate’, тобто об’єднувати, і
вона виводить вміст файлів один за одним. У цьому випадку є лише один
файл, тому cat просто виводить нам його вміст:
ВИХІД
  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total
Виведення сторінки за сторінкою
У цьому уроці, для зручності та послідовності ми й надалі
використовуватимемо команду cat, але її недолік полягає в
тому, що вона завжди показує весь файл одразу. Більш корисною на
практиці є команда less (наприклад,
less lengths.txt). Вона виводить стільки вмісту файлу,
скільки вміщується в одному екрані, а потім робить паузу. Ви можете
перейти на один екран вперед, натиснувши пробіл, або на один екран
назад, натиснувши клавішу b. Щоб вийти з перегляду вмісту
файлу, натисніть q.
Фільтрування виводу
Далі ми скористаємося командою sort для сортування
вмісту файлу lengths.txt. Але спершу виконаємо вправу, щоб
трохи ознайомитися з командою sort:
Що робить sort -n?
Файл shell-lesson-data/exercise-data/numbers.txt містить
наступні рядки:
10
2
19
22
6
Якщо ми виконаємо команду sort для цього файлу, то
отримаємо наступне:
ВИХІД
10
19
2
22
6
Якщо ми виконаємо команду sort -n для того ж файлу, то
замість цього ми отримаємо наступне:
ВИХІД
2
6
10
19
22
Поясніть, чому -n має такий ефект.
Опція -n задає числове, а не алфавітно-цифрове
сортування.
Ми також використовуватимемо опцію -n, щоб задати
числове сортування замість алфавітно-цифрового. Це не змінить
файл; натомість відсортований результат буде виведено на екран:
ВИХІД
  9  methane.pdb
 12  ethane.pdb
 15  propane.pdb
 20  cubane.pdb
 21  pentane.pdb
 30  octane.pdb
107  total
Ми можемо записати відсортований список рядків в інший тимчасовий
файл з назвою sorted-lengths.txt, додавши
> sorted-lengths.txt після команди, так само як ми
використовували > lengths.txt, щоб записати вивід
wc у lengths.txt. Потім можна скористатися
командою head, щоб отримати перші кілька рядків у
sorted-lengths.txt:
ВИХІД
  9 methane.pdb
Використання -n 1 з head вказує команді, що
нам потрібен лише перший рядок файлу; -n 20 поверне перші
20 тощо. Оскільки файл sorted-lengths.txt містить довжини
наших файлів, впорядковані від найменшої до найбільшої, виведенням
head має бути файл з найменшою кількістю рядків.
Що означає >>?
Ми вже розглядали оператор >, але ще існує схожий
оператор >>, який працює трохи інакше. Ми дізнаємося
про відмінності між цими двома операторами, надрукувавши кілька рядків.
Для виведення рядків ми можемо скористатися командою echo,
наприклад:
ВИХІД
The echo command prints text
Тепер протестуйте наведені нижче команди, щоб виявити різницю між цими двома операторами:
та:
Підказка: Спробуйте виконати кожну команду двічі поспіль, а потім переглянути вихідні файли.
У першому прикладі з > рядок ‘hello’ записується до
файлу testfile01.txt, але файл перезаписується кожного
разу, коли ми запускаємо команду.
З другого прикладу ми бачимо, що оператор >> також
записує рядок ‘hello’ у файл (у цьому випадку
testfile02.txt), але додає рядок до файлу, якщо останній
вже існує (тобто, коли ми запускаємо його вдруге).
Додавання даних у кінець файлу
Ми вже знайомі з командою head, яка виводить рядки з
початку файлу. Команда tail схожа на неї, але виводить
рядки з кінця файлу.
Розглянемо файл
shell-lesson-data/exercise-data/animal-counts/animals.csv.
Після виконання цих команд оберіть відповідь, яка відповідає вмісту
файлу animals-subset.csv:
- Перші три рядки файлу 
animals.csv - Останні два рядки файлу 
animals.csv - Перші три рядки та останні два рядки файлу
animals.csv - Другий і третій рядки файлу 
animals.csv 
Варіант 3 є правильним. Щоб варіант 1 був правильним, потрібно
виконати лише команду head. Щоб варіант 2 був правильним,
нам слід виконати лише команду tail. Щоб варіант 4 був
коректним, нам слід передати вивід команди head у команду
tail -n 2 виконавши
head -n 3 animals.csv | tail -n 2 > animals-subset.csv
Передача виводу іншій команді
У нашому прикладі для пошуку файлу з найменшою кількістю рядків, ми
використовуємо два проміжні файли lengths.txt та
sorted-lengths.txt для зберігання результатів. Такий підхід
може збивати з пантелику, оскільки навіть зрозумівши як працюють
wc, sort і head, ці проміжні
файли ускладнюють відстеження всього процесу. Щоб легше було зрозуміти,
можна одночасно виконати sort і head:
ВИХІД
  9 methane.pdb
Вертикальна риска | між двома командами називається
каналом (pipe). Вона вказує терміналу, що вивід команди
ліворуч слід використати як вхідні дані для команди праворуч.
Це усуває необхідність у файлі sorted-lengths.txt.
Поєднання декількох команд
Ніщо не заважає нам з’єднувати канали послідовно. Наприклад, ми
можемо надсилати вивід wc безпосередньо до
sort, а потім результат — до head. Це усуває
необхідність у будь-яких проміжних файлах.
Ми почнемо з використання каналу для надсилання виводу
wc до sort:
ВИХІД
   9 methane.pdb
  12 ethane.pdb
  15 propane.pdb
  20 cubane.pdb
  21 pentane.pdb
  30 octane.pdb
 107 total
Потім ми можемо передати цей вивід через інший канал до
head, отже повний конвеєр буде мати наступний вигляд:
ВИХІД
   9 methane.pdb
Це подібне тому, як в математиці ми розглядаємо складні функції на
кшталт log(3x) і кажемо ‘логарифм трьох x*’. У нашому випадку,
обчислюється ‘head від sort від підрахунку кількості рядків у файлах
*.pdb’.
Перенаправлення та канали, використані в останніх кількох командах, проілюстровані нижче:
З’єднання команд у конвеєр
У нашому поточному каталозі ми хочемо знайти 3 файли, які мають найменшу кількість рядків. Яка з наведених нижче команд підійде для цього?
wc -l * > sort -n > head -n 3wc -l * | sort -n | head -n 1-3wc -l * | head -n 3 | sort -nwc -l * | sort -n | head -n 3
Варіант 4 є рішенням. Символ каналу | використовується
для під’єднання виводу однієї команди до входу іншої. Символ
> використовується для перенаправлення стандартного
виводу до файлу. Спробуйте це у каталозі
shell-lesson-data/exercise-data/proteins!
Інструменти, створені для співробітництва
Представлена вище можливість комбінування програм є причиною успіху
Unix. Замість створення величезних програми, які намагаються робити
багато різних речей, розробники Unix зосередилися на створенні численних
простих інструментів, кожен з яких добре виконує одну роботу і при цьому
чудово взаємодіє з іншими. Ця модель програмування називається ‘канали
та фільтри’. Ми вже бачили приклад каналів; а
фільтри — це програми на кшталт wc або
sort, які перетворюють потік вхідних даних у потік
вихідних. Майже всі стандартні інструменти Unix можуть працювати таким
чином. Якщо їм не вказано робити інше, такі програми читають дані зі
стандартного вводу, виконують з ними певні дії та записують результат у
стандартний вивід.
Головне полягає в тому, що будь-яка програма, яка зчитує рядки тексту зі стандартного вводу і записує їх у стандартний вивід, може бути об’єднана з будь-якою іншою програмою, яка працює так само. Ви можете і повинні писати свої програми таким чином, щоб ви та інші люди могли з’єднувати їх через канали і тим самим суттєво збільшуючи їхню потужність.
Розуміння роботи з каналами
Файл з назвою animals.csv (у каталозі
shell-lesson-data/exercise-data/animal-counts) містить
наступні дані:
2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1
Який текст проходить через кожен із каналів та фінальне
перенаправлення у конвеєрі нижче? Зауважте, що команда
sort -r сортує у зворотному порядку.
Підказка: створюйте конвеєр по одній команді за раз, щоб перевіряти своє розуміння
Команда head виділяє перші 5 рядків з файлу
animals.csv. Потім останні 3 рядки виділяються з попередніх
5 за допомогою команди tail. За допомогою команди
sort -r ці 3 рядки сортуються у зворотному порядку. І
нарешті, результат перенаправляється до файлу final.txt.
Вміст цього файлу можна перевірити, виконавши команду
cat final.txt. Файл повинен містити наступні рядки:
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-05,raccoon,7
Конструювання каналу
Для файлу animals.csv з попередньої вправи розглянемо
наступну команду:
Команда cut використовується для видалення або
‘вирізання’ певних частин кожного рядка у файлі. Вона очікує, що рядки
буде розділено на стовпчики символом Tab. Символ, який
використовується таким чином, називається роздільником.
У наведеному вище прикладі ми використали опцію -d, щоб
вказати кому як роздільник. Ми також використали опцію -f,
щоб зазначити, що ми хочемо вилучити друге поле (стовпчик). Це призведе
до наступного результату:
ВИХІД
deer
rabbit
raccoon
rabbit
deer
fox
rabbit
bear
Команда uniq відфільтровує сусідні однакові рядки у
файлі. Як можна розширити цей конвеєр (за допомогою uniq та
інших команд), щоб з’ясувати, назви яких тварин містяться у файлі (без
повторень у їхніх назвах)?
Який з каналів використати?
Файл animals.csv містить 8 рядків даних, відформатованих
наступним чином:
ВИХІД
2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
...
Команда uniq має опцію -c, яка підраховує
кількість разів, коли рядок зʼявляється у вхідних даних. Припускаючи що
ваш поточний каталог має назву
shell-lesson-data/exercise-data/animal-counts, яку команду
слід використати, щоб створити таблицю у файлі з підрахунком загальної
кількості тварин кожного типу?
sort animals.csv | uniq -csort -t, -k2,2 animals.csv | uniq -ccut -d, -f 2 animals.csv | uniq -ccut -d, -f 2 animals.csv | sort | uniq -ccut -d, -f 2 animals.csv | sort | uniq -c | wc -l
Варіант 4. Це правильна відповідь. Якщо вам важко зрозуміти, чому,
спробуйте виконати команди або фрагменти конвеєру (перед цим
переконайтеся, що ви перебуваєте у каталозі
shell-lesson-data/exercise-data/animal-counts).
Конвеєр Неллі: перевірка файлів
Неллі обробила свої зразки в аналізаторах і створила 17 файлів в
каталозі north-pacific-gyre, описаному раніше. Для швидкої
перевірки, вона переходить у каталог shell-lesson-data та
набирає:
На виході вона отримує 18 рядків, які виглядають наступним чином:
ВИХІД
300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
300 NENE01751B.txt
300 NENE01812A.txt
... ...
Тепер вона набирає наступне:
ВИХІД
 240 NENE02018B.txt
 300 NENE01729A.txt
 300 NENE01729B.txt
 300 NENE01736A.txt
 300 NENE01751A.txt
Ого - несподіванка! Один з файлів на 60 рядків коротший за інші. Коли вона повертається до цього файлу та перевіряє його, вона бачить, що зробила цей аналіз о 8:00 ранку в понеділок — хтось, можливо, користувався машиною на вихідних, і вона забула її перезавантажити. Перед тим, як повторно проаналізувати цей зразок, вона перевіряє, чи є файли, що містять забагато даних:
ВИХІД
 300 NENE02040B.txt
 300 NENE02040Z.txt
 300 NENE02043A.txt
 300 NENE02043B.txt
5040 total
Ці цифри мають сенс — але що робить ця ‘Z’ у другому рядку? Всі її зразки мають бути позначені ‘A’ або ‘B’; за попередньою домовленістю її лабораторія використовує ‘Z’ для позначення зразків з недостатньою інформацією. Щоб знайти інші подібні зразки, вона робить наступне:
ВИХІД
NENE01971Z.txt    NENE02040Z.txt
Справді, коли вона перевіряє файл журналу на своєму ноутбуці, то
виявляється, що глибина не була записана для жодного з цих зразків.
Оскільки отримати цю інформацію іншим способом вже неможливо, їй
доведеться виключити ці два файли з аналізу. Вона може видалити їх за
допомогою rm, але деякі подальші аналізи даних не
вимагатимуть інформації про глибину, тому їй буде потрібно обережно
обирати файли за допомогою шаблонів
NENE*A.txt NENE*B.txt.
Видалення непотрібних файлів
Припустимо, ви хочете видалити файли з обробленими даними й зберегти
лише вихідні файли та скрипт обробки для економії місця у сховищі.
Вихідні файли закінчуються на .dat, а оброблені файли
закінчуються на .txt. Яка з наведених нижче команд видалить
усі оброблені файли даних і тільки їх?
rm ?.txtrm *.txtrm * .txtrm *.*
Це призведе до вилучення файлів
.txtз односимвольними назвамиЦе правильна відповідь
Термінал розширить шаблон
*до переліку усіх файлів у поточному каталозі, таким чином, команда спробує видалити всі знайдені файли та додатковий файл з назвою `.txt’Термінал розширює
*.*до переліку усіх файлів, назви яких містять принаймні одну крапку (.), включно з обробленими файлами (.txt), і вихідними файлами (.dat)
- 
wcпідраховує рядки, слова та символи у своїх вхідних даних. - 
catвиводить вміст своїх вхідних даних. - 
sortсортує вхідні дані. - 
headза замовчуванням (тобто без додаткових аргументів) виводить перші 10 рядків вхідних даних. - 
tailза замовчуванням (тобто без додаткових аргументів) виводить останні 10 рядків вхідних даних. - 
command > [file]перенаправляє вивід команди у файл (перезаписуючи будь-який наявний вміст цього файлу, якщо файл вже існує). - 
command >> [file]додає вивід команди до файлу. - 
[first] | [second]є конвеєром: вихід першої команди використовується як вхідні дані для другої. - Найкращий спосіб використання терміналу - це комбінування простих однозадачних програм (фільтрів) за допомогою каналів.