Канали та фільтри
Огляд
Викладання: 25 хв
Вправи: 10 хвПитання
Як я можу комбінувати команди, що вже існують, щоб робити нові речі?
Цілі
Перенаправити вивід команди до файлу.
Створити конвеєри команд з двома та більше ступенями.
Пояснити, що зазвичай відбувається, якщо програмі або конвеєру не надається жодних вхідних даних для обробки.
Пояснити перевагу поєднання команд з каналами та фільтрами.
Тепер, коли ми знаємо декілька основних команд,
ми можемо нарешті розглянути найпотужнішу можливість терміналу:
легкість, з якою він дозволяє нам комбінувати програми, що існують, новими способами.
Ми почнемо з каталогу shell-lesson-data/exercise-data/proteins,
який містить шість файлів, що описують деякі прості органічні молекули.
Розширення .pdb вказує на те, що ці файли у форматі Protein Data Bank,
простому текстовому форматі, який визначає тип і положення кожного атома в молекулі.
$ ls
cubane.pdb methane.pdb pentane.pdb
ethane.pdb octane.pdb propane.pdb
Запустимо приклад команди:
$ wc cubane.pdb
20 156 1158 cubane.pdb
wc - команда ‘порахуй слова’ (англ. ‘word count’):
вона підраховує кількість рядків, слів і символів у файлах (зліва направо, у такому порядку).
Якщо ми виконаємо команду wc *.pdb, то * у *.pdb збігається з нулем або більшою кількістю символів,
тож термінал перетворить *.pdb на перелік усіх .pdb-файлів у поточному каталозі:
$ wc *.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,
у виводі буде показано лише кількість рядків у файлі:
$ wc -l *.pdb
20 cubane.pdb
12 ethane.pdb
9 methane.pdb
30 octane.pdb
21 pentane.pdb
15 propane.pdb
107 total
Параметри -m і -w також можна використовувати з командою wc, щоб показати
тільки кількість символів або тільки кількість слів у файлах.
Чому воно нічого не робить?
Що станеться, якщо команда має обробити файл, але ми не вкажемо імені файлу? Наприклад, що буде, якщо ми наберемо:
$ wc -lале не будемо вводити
*.pdb(або щось інше) після команди? Оскільки команда не має жодних назв файлів,wcвважає, що вона повинна обробляти дані, введені у командному рядку, тож вона просто сидить і чекає, поки ми надамо їй інтерактивно якісь дані. Ззовні, однак, все, що ми бачимо, це те, що вона, здається, нічого не робить.Якщо ви припустилися такої помилки, ви можете вийти з цього стану, утримуючи клавішу control (Ctrl), один раз натиснувши клавішу C, відпустивши після цього клавішу Ctrl. Ctrl+C
Перехоплення виводу з команд
Який з цих файлів містить найменше рядків? На це питання легко відповісти, коли файлів всього шість, але що, якщо їх 6000? Наш перший крок до пошуку рішеня - це запуск команди:
$ wc -l *.pdb > lengths.txt
Символ ‘більше ніж’, >, вказує терміналу перенаправити вивід команди
до файла замість виведення його на екран. (Саме тому виведення на екран не відбувається:
все, що мала вивести команда wc, було збережено у файлі
lengths.txt замість цього). Термінал створить
файл, якщо його не існує. Якщо файл існує, його буде
буде перезаписано без будь-яких повідомлень, що може призвести до втрати даних, а отже, вимагає
певної обережності.
Файл ls lengths.txt підтверджує, що файл існує:
$ ls lengths.txt
lengths.txt
Тепер ми можемо вивести вміст файлу lengths.txt на екран за допомогою команди cat lengths.txt.
Команда cat отримала свою назву від слова ‘concatenate’, тобто об’єднувати,
і вона виводить вміст файлів один за одним.
У цьому випадку є лише один файл,
тому cat просто відображає нам його вміст:
$ cat lengths.txt
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, щоб вказати, що сортування буде
числовим, а не алфавітно-цифровим.
Це не змінить файл;
натомість відсортований результат буде виведено на екран:
$ sort -n lengths.txt
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:
$ sort -n lengths.txt > sorted-lengths.txt
$ head -n 1 sorted-lengths.txt
9 methane.pdb
Використання -n 1 з head говорить команді, що
нам потрібен лише перший рядок файлу;
-n 20 отримає перші 20,
і так далі.
Оскільки файл sorted-lengths.txt містить довжини наших файлів, впорядковані від найменшої до найбільшої,
виведенням head має бути файл з найменшою кількістю рядків.
Перенаправлення у той самий файл
Це дуже погана ідея - намагатися перенаправити вихідні дані команди, яка оперує з файлом, у той самий файл. Наприклад:
$ sort -n lengths.txt > lengths.txtВиконання таких дій може надати вам некоректні результати та/або видалити вміст файлу
lengths.txt.
Що означає
>>?Ми бачили використання оператору
>, але існує схожий оператор>>, який працює дещо по-іншому. Ми дізнаємося про відмінності між цими двома операторами, надрукувавши кілька рядків. Ми можемо скористатися командоюechoдля виведення рядків, наприклад$ echo Команда echo виводить текстКоманда echo виводить текстТепер протестуйте наведені нижче команди, щоб виявити різницю між цими двома операторами:
$ echo hello > testfile01.txtта:
$ echo hello >> testfile02.txtПідказка: Спробуйте виконати кожну команду двічі поспіль, а потім переглянути вихідні файли.
Розв’язання
У першому прикладі з
>рядок ‘hello’ записується до файлуtestfile01.txt, але файл перезаписується кожного разу, коли ми запускаємо команду.З другого прикладу ми бачимо, що оператор
>>також записує рядок ‘hello’ у файл (у цьому випадкуtestfile02.txt), але додає рядок до файлу, якщо останній вже існує (тобто, коли ми запускаємо його вдруге).
Додавання даних
Ми вже зустрічалися з командою
head, яка друкує рядки з початку файлу. Командаtailсхожа на неї, але друкує рядки з кінця файлу.Розглянемо файл
shell-lesson-data/exercise-data/animal-counts/animals.csv. Після виконання цих команд виберіть відповідь, яка відповідає файлуanimals-subset.csv:$ head -n 3 animals.csv > animals-subset.csv $ tail -n 2 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 разом:
$ sort -n lengths.txt | head -n 1
9 methane.pdb
Вертикальна риска | між двома командами називається каналом.
Він вказує терміналу, що ми хочемо використовувати
вивід команди ліворуч
як вхідні дані для команди праворуч.
Це усунуло необхідність у файлі sorted-lengths.txt.
Поєднання декількох команд
Ніщо не заважає нам з’єднувати канали послідовно.
Ми можемо, наприклад, надсилати вивід wc безпосередньо до sort,
а потім отриманий результат - до head.
Це усуває необхідність у будь-яких проміжних файлах.
Ми почнемо з використання каналу для відправки виводу wc до sort:
$ wc -l *.pdb | sort -n
9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
107 total
Потім ми можемо відправити цей вивід через інший канал в head, отже конвеєр стає наступним:
$ wc -l *.pdb | sort -n | head -n 1
9 methane.pdb
Це точно так само, як математик вкладає функції на кшталт log(3x)
і каже ‘логарифм трьох, помноженого на x’.
У нашому випадку,
обчислюється ‘head від sort від підрахунку кількості рядків у файлах *.pdb’.
Перенаправлення та канали, використані в останніх кількох командах, проілюстровано нижче:
З’єднання команд у конвеєр
У нашому поточному каталозі ми хочемо знайти 3 файли, які мають найменшу кількість рядків. Яка з наведених нижче команд підійде для цього?
wc -l * > sort -n > head -n 3.wc -l * | sort -n | head -n 1-3.wc -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сортує у зворотному порядку.$ cat animals.csv | head -n 5 | tail -n 3 | sort -r > final.txtПідказка: створюйте конвеєр по одній команді за раз, щоб перевірити своє розуміння
Розв’язання
Команда
headвитягує перші 5 рядків з файлуanimals.csv. Потім останні 3 рядки витягуються з попередніх 5 за допомогою командиtail. За допомогою командиsort -rці 3 рядки сортуються у зворотному порядку і нарешті, виведення перенаправляється до файлуfinal.txt. Вміст цього файлу можна перевірити, виконавши командуcat final.txt. Файл повинен містити наступні рядки:2012-11-06,rabbit,19 2012-11-06,олень,2 2012-11-05,єнот,7
Конструювання каналу
Для файлу
animals.csvз попередньої завдання розглянемо наступну команду:>$ cut -d , -f 2 animals.csvКоманда
cutвикористовується для видалення або ‘вирізання’ певних частин кожного рядка у файлі, іcutочікує, що рядки буде розділено на стовпчики символом Tab. Символ, який використовується таким чином, називається відокремлювальним символом. У наведеному вище прикладі ми використовуємо опцію-d, щоб вказати кому як відокремлювальний символ. Ми також використали опцію-f, щоб вказати, що ми хочемо вилучити друге поле (стовпчик). Це призведе до наступного результату:deer rabbit raccoon rabbit deer fox rabbit bearКоманда
uniqвідфільтровує сусідні однакові рядки у файлі. Як можна розширити цей конвеєр (за допомогоюuniqта іншої команди), щоб з’ясувати, які тварини містяться у файлі (без повторень у їхніх назвах)?Розв’язання
$ cut -d , -f 2 animals.csv | sort | 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 -c.sort -t, -k2,2 animals.csv | uniq -c.cut -d, -f 2 animals.csv | uniq -ccut -d, -f 2 animals.csv | sort | uniq -c.cut -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, Неллі набирає:
$ cd north-pacific-gyre
$ wc -l *.txt
На виході вона отримує 18 рядків, які виглядають наступним чином:
300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
300 NENE01751B.txt
300 NENE01812A.txt
... ...
Тепер вона набирає наступне:
$ wc -l *.txt | sort -n | head -n 5
240 NENE02018B.txt
300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
Упс: один з файлів на 60 рядків коротший за інші. Коли вона повертається і перевіряє його, вона бачить, що зробила цей аналіз о 8:00 ранку в понеділок — хтось, можливо, користувався машиною на вихідних, і вона забула її перезавантажити. Перед тим, як повторно проаналізувати цей зразок, вона перевіряє, чи є файли, що містять забагато даних:
$ wc -l *.txt | sort -n | tail -n 5
300 NENE02040B.txt
300 NENE02040Z.txt
300 NENE02043A.txt
300 NENE02043B.txt
5040 total
Ці цифри виглядають добре — але що робить ця ‘Z’ у передостанньому рядку? Всі її зразки мають бути позначені ‘A’ або ‘B’; за попередньою домовленістю її лабораторія використовує ‘Z’ для позначення зразків з недостатньою інформацією. Щоб знайти подібні зразки, вона робить наступне:
$ ls *Z.txt
NENE01971Z.txt NENE02040Z.txt
Звісно,
коли вона перевіряє журнал на своєму ноутбуці,
глибина не записана для жодного з цих зразків.
Оскільки вже занадто пізно отримати інформацію в інший спосіб,
вона повинна виключити ці два файли з аналізу.
Вона може видалити їх за допомогою rm,
але насправді є деякі аналізи, які вона може зробити пізніше, де глибина не має значення,
тож натомість, пізніше їй доведеться бути обережною і вибирати файли за допомогою підстановочних виразів
NENE*A.txt NENE*B.txt.
Видалення непотрібних файлів
Припустимо, ви хочете видалити файли оброблених даних і зберегти лише сирі файли і скрипт обробки для економії місця у сховищі. Вихідні файли закінчуються на
.dat, а оброблені файли закінчуються на.txt. Яка з наведених нижче команд видалить усі оброблені файли даних, і лише оброблені файли даних?
rm ?.txtrm *.txtrm * .txtrm *.*Розв’язання
- Це призведе до вилучення файлів
.txtз односимвольними назвами- Це правильна відповідь
- Термінал розширить підстановочний символ
*так, щоб він відповідав усім файлам у поточному каталозі, таким чином, команда спробує видалити всі знайдені файли і додатковий файл з назвою `.txt’.- Термінал розширить
*.*, щоб знайти всі файли з будь-яким розширенням, таким чином, ця команда видалить усі файли.
[workshop-repo]: [yaml]: http://yaml.org/
Ключові моменти
wcпідраховує рядки, слова та символи у вхідних даних.cat` виводить вміст своїх вхідних даних.
sortсортує вхідні дані.
headвиводить перші 10 рядків вхідних даних.
tailвиводить останні 10 рядків вхідних даних.
command > [file]перенаправляє вивід команди у файл (перезаписуючи наявний вміст).
command >> [file]додає вивід команди до файлу.
[first] | [second]є конвеєром: вихід першої команди використовується як вхід для другої.Найкращий спосіб використання терміналу - це використання каналів для об’єднання простих одноцільових програм (фільтрів).