Поиск по сайту:

Как использовать каналы в 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 начинает оживать для вас, и вы получаете совершенно новые возможности, когда можете организовать набор команд для создания единой связной работы.

Подсказка на прощание: лучше всего писать свои конвейерные команды, добавляя по одной команде за раз и заставляя эту часть работать, а затем добавляя следующую команду.