Как использовать каналы в Linux
Используйте конвейеры Linux, чтобы организовать совместную работу утилит командной строки. Упростите сложные процессы и повысьте производительность, используя набор автономных команд и превратив их в целеустремленную команду. Мы покажем вам, как это сделать.
Трубы везде
Каналы — одна из самых полезных функций командной строки, которые есть в Linux и Unix-подобных операционных системах. Трубы используются по-разному. Посмотрите любую статью о командной строке Linux — на любом веб-сайте, не только на нашем, — и вы увидите, что каналы появляются чаще, чем нет. Я просмотрел некоторые статьи How-To Geek по Linux, и во всех них так или иначе используются каналы.
Каналы Linux позволяют выполнять действия, которые не поддерживаются оболочкой «из коробки». Но поскольку философия дизайна Linux состоит в том, чтобы иметь много небольших утилит, которые очень хорошо выполняют свою функцию и не имеют ненужной функциональности (мантра «делай одно дело, и делай это хорошо»), вы можете соединять строки команд вместе с конвейерами, чтобы выходные данные одной команды становится вводом другой. Каждая команда, которую вы передаете, привносит в команду свой уникальный талант, и вскоре вы обнаружите, что собрали команду-победителя.
Простой пример
Предположим, у нас есть каталог, полный файлов разных типов. Мы хотим знать, сколько файлов определенного типа находится в этом каталоге. Есть и другие способы сделать это, но целью этого упражнения является введение каналов, поэтому мы собираемся сделать это с помощью каналов.
Мы можем легко получить список файлов, используя ls
:
ls
Чтобы выделить интересующий тип файла, мы будем использовать grep
. Мы хотим найти файлы, в имени или расширении которых есть слово «страница».
Мы будем использовать специальный символ оболочки «|
» для передачи вывода из ls
в grep
.
ls | grep "page"
grep
выводит строки, соответствующие шаблону поиска. Итак, это дает нам список, содержащий только файлы «.page».
Даже этот тривиальный пример демонстрирует функциональность каналов. Вывод из ls
не был отправлен в окно терминала. Он был отправлен в grep
как данные для работы с командой grep
. Вывод, который мы видим, исходит от grep
– последней команды в этой цепочке.
Расширение нашей цепочки
Давайте начнем расширять нашу цепочку конвейерных команд. Мы можем подсчитать файлы «.page», добавив команду wc
. Мы будем использовать параметр -l
(количество строк) с wc
. Обратите внимание, что мы также добавили параметр -l
(длинный формат) в ls
. Мы будем использовать это в ближайшее время.
ls - | grep "page" | wc -l
grep
больше не является последней командой в цепочке, поэтому мы не видим ее вывод. Вывод grep
передается в команду wc
. Вывод, который мы видим в окне терминала, получен из wc
. wc
сообщает, что в каталоге есть 69 файлов «.page».
Давайте продлим вещи снова. Мы уберем команду wc
из командной строки и заменим ее на awk
. В выводе ls
есть девять столбцов с опцией -l
(длинный формат). Мы будем использовать awk
для вывода пятого, третьего и девятого столбцов. Это размер, владелец и имя файла.
ls -l | grep "page" | awk '{print $5 " " $3 " " $9}'
Мы получаем список этих столбцов для каждого из соответствующих файлов.
Теперь мы передадим этот вывод через команду sort
. Мы будем использовать параметр -n
(числовой), чтобы сообщить sort
, что первый столбец следует рассматривать как числа.
ls -l | grep "page" | awk '{print $5 " " $3 " " $9}' | sort -n
Вывод теперь сортируется по размеру файла с нашим настраиваемым выбором из трех столбцов.
Добавление другой команды
Мы закончим, добавив команду tail
. Мы скажем ему отображать только последние пять строк вывода.
ls -l | grep "page" | awk '{print $5 " " $3 " " $9}' | sort -n | tail -5
Это означает, что наша команда переводится как «покажите мне пять самых больших файлов «.page» в этом каталоге, упорядоченных по размеру». Конечно, для этого нет команды, но с помощью пайпов мы создали свои собственные. Мы могли бы добавить эту или любую другую длинную команду в качестве псевдонима или функции оболочки, чтобы сохранить весь набор текста.
Вот результат:
Мы могли бы изменить порядок размеров, добавив параметр -r
(обратный) к команде sort
и используя head
вместо tail
, чтобы выбрать строки в верхней части вывода.
На этот раз пять самых больших файлов «.page» перечислены от самого большого к самому маленькому:
Некоторые недавние примеры
Вот два интересных примера из недавних статей How-To для гиков.
Некоторые команды, такие как xargs
, спроектированы таким образом, чтобы входные данные передавались им по конвейеру. Вот как мы можем заставить wc
подсчитывать слова, символы и строки в нескольких файлах, передав ls
в xargs
, который затем передает список имен файлов в wc
, как если бы они были переданы в wc
в качестве параметров командной строки.
ls *.page | xargs wc
Общее количество слов, символов и строк указано в нижней части окна терминала.
Вот способ получить отсортированный список уникальных расширений файлов в текущем каталоге с подсчетом каждого типа.
ls | rev | cut -d'.' -f1 | rev | sort | uniq -c
Здесь многое происходит.
- ls: список файлов в каталоге
- rev: инвертирует текст в именах файлов.
- cut: обрезает строку при первом появлении указанного разделителя «.». Текст после этого отбрасывается.
- rev: инвертирует оставшийся текст, который является расширением имени файла.
- sort: сортирует список в алфавитном порядке.
- uniq: подсчитывает количество каждой уникальной записи в списке.
Вывод показывает список расширений файлов, отсортированных в алфавитном порядке с количеством каждого уникального типа.
Именованные каналы
Нам доступен еще один тип канала, называемый именованным каналом. Каналы в предыдущих примерах создаются оболочкой «на лету» при обработке командной строки. Трубы создаются, используются, а затем выбрасываются. Они преходящи и не оставляют следов. Они существуют только до тех пор, пока выполняется команда, использующая их.
Именованные каналы появляются в файловой системе как постоянные объекты, поэтому вы можете увидеть их с помощью ls
. Они постоянны, потому что переживут перезагрузку компьютера, хотя любые непрочитанные данные в них в это время будут удалены.
Именованные каналы часто использовались когда-то, чтобы позволить различным процессам отправлять и получать данные, но я давно не видел, чтобы они использовались таким образом. Без сомнения, есть люди, которые все еще используют их с большим успехом, но я не встречал их в последнее время. Но для полноты картины или просто для удовлетворения вашего любопытства, вот как вы можете их использовать.
Именованные каналы создаются командой mkfifo
. Эта команда создаст именованный канал с именем «geek-pipe» в текущем каталоге.
mkfifo geek-pipe
Мы можем увидеть детали именованного канала, если воспользуемся командой ls
с параметром -l
(длинный формат):
ls -l geek-pipe
Первый символ в списке — «p», что означает трубу. Если бы это было «d», это означало бы, что объект файловой системы является каталогом, а тире «-» означало бы, что это обычный файл.
Использование именованного канала
Используем нашу трубу. Безымянные каналы, которые мы использовали в наших предыдущих примерах, передавали данные немедленно от команды-отправителя к команде-получателю. Данные, отправленные через именованный канал, останутся в канале до тех пор, пока не будут прочитаны. Данные фактически хранятся в памяти, поэтому размер именованного канала не будет меняться в списках ls
независимо от того, есть в нем данные или нет.
В этом примере мы будем использовать два окна терминала. Я буду использовать ярлык:
# Terminal-1
в одном окне терминала и
# Terminal-2
в другом, так что вы можете различать их. Хэш «#» сообщает оболочке, что далее следует комментарий, и что следует его игнорировать.
Давайте возьмем весь наш предыдущий пример и перенаправим его в именованный канал. Таким образом, мы используем как безымянный, так и именованный каналы в одной команде:
ls | rev | cut -d'.' -f1 | rev | sort | uniq -c > geek-pipe
Ничего особенного не произойдет. Вы можете заметить, что вы не возвращаетесь в командную строку, значит, что-то происходит.
В другом окне терминала введите следующую команду:
cat < geek-pipe
Мы перенаправляем содержимое именованного канала в cat
, чтобы cat
отображал это содержимое во втором окне терминала. Вот результат:
И вы увидите, что вас вернули в командную строку в первом окне терминала.
Итак, что только что произошло.
- Мы перенаправили некоторые выходные данные в именованный канал.
- Первое окно терминала не вернулось в командную строку.
- Данные оставались в канале до тех пор, пока они не были прочитаны из канала на втором терминале.
- Мы вернулись в командную строку в первом окне терминала.
Вы можете подумать, что можете запустить команду в первом окне терминала в качестве фоновой задачи, добавив &
в конец команды. И вы будете правы. В этом случае мы были бы немедленно возвращены в командную строку.
Суть не использования фоновой обработки заключалась в том, чтобы подчеркнуть, что именованный канал является блокирующим процессом. Помещение чего-либо в именованный канал открывает только один конец канала. Другой конец не открывается, пока программа чтения не извлечет данные. Ядро приостанавливает процесс в первом окне терминала до тех пор, пока данные не будут прочитаны с другого конца канала.
Сила труб
В настоящее время именованные каналы являются чем-то вроде новинки.
Обычные старые Linux-каналы, с другой стороны, являются одним из самых полезных инструментов, которые вы можете иметь в своем наборе инструментов окна терминала. Командная строка Linux начинает оживать для вас, и вы получаете совершенно новые возможности, когда можете организовать набор команд для создания единой связной работы.
Подсказка на прощание: лучше всего писать свои конвейерные команды, добавляя по одной команде за раз и заставляя эту часть работать, а затем добавляя следующую команду.