Используйте pipe для постраничного отображения результатов ubuntu

Обновлено: 03.07.2024

Какие только термины не используют в русском языке для перевода слова "pipes": и трубы, и трубопроводы, и конвейеры, и потоки, и прочее. В контексте все эти термины выглядят довольно неуклюже. И вот еще беда - ни от одного из этих существительных нельзя образовать глагол, не говоря уже о том, чтобы называть так символ вертикальной черты. Можно, правда, употребить глагол "конвейеризировать", но такое не написать, не выговорить невозможно. Я пытался делать наметки этой статьи, используя все перечисленные термины, но не был удовлетворен ни одним.

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

Предисловие

В одной остроумной статье я прочел следующую сентенцию: "Лишить приверженца Юникс программных каналов, то же самое, что отобрать мышь у пользователя Виндоуз". Возможно, в этом утверждении и есть некоторое преувеличение, но в прежние времена так оно, по большому счету, и было. Опытные сторонники Юниксовидных систем любят консоль и умеют ею пользоваться. Мы же, нынешние, установив Убунту, уже считаем себя линуксоидами, а что такое консоль, имеем смутное представления. Но проходит некоторое время, и, устав от украшения рабочего стола, прочитав две-три статейки, мы решаемся нажать мышкой на значок монитора в системном трее. Со временем перед нами открывается новый мир, полный удивительных возможностей и беспрерывного совершенствования своих знаний, мир пиршества интеллекта, непрекращающегося эксперимента, и радости оттого, что ты Homo Sapiens. Девиз: "Вернем радость в общение с компьютером!", - как нельзя лучше подходит для этого случая.

Предлагаемая вашему вниманию статья как раз для тех, кто недавно открыл для себя командную строку Линукс.

Введение в программные каналы

Программным каналом называется использование вывода одной команды в качестве ввода для другой программы. Например:

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

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

По умолчанию, стандартный ввод осуществляется с клавиатуры, а стандартный вывод - на экран монитора. Если же мы задействуем оператор программных каналов (|), то стандартный вывод первой программы станет стандартным вводом второй, при этом на экране монитора он уже не появится.

Такая цепочка вовсе не ограничивается двумя программами, но может продолжаться сколь угодно долго.

Как это работает

В большинстве Юниксовидных систем все процессы в программном канале начинаются одновременно, их потоки соответственно соединяются и управляются планировщиком вместе со всеми остальными процессами, идущими в системе.

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

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

Как пользоваться программными каналами

Чаще всего употребляются программные каналы, заканчивающиеся командами less и more. Эти две команды схожи по своему действию, однако less новее и имеет ряд дополнительных функций, включая возможность вернуться к предыдущим "страницам" вывода. Многие пользуются этими программными каналами, не подозревая, что занимаются столь мудреными вещами.

Кроме вышеприведенного примера с каналом dmesg | less , часто используется канал ls | less . Команда ls позволяет просматривать содержимое директорий, а с опцией -l дает подробные сведения о файлах, "населяющих" указанную директорию. Если директория содержит достаточно файлов, чтобы их список занял больше одного экрана, то применение программного канала с less или more неизбежно:

Для пробы проделайте такой пример:

Только запаситесь терпением - на моей небольшой системе, установленной с одного CD, в выводе было 87 187 строк, сиречь файлов. Дело в том, что опция -R команды ls выводит содержимое директории рекурсивно, то есть открывая подкаталоги, подкаталоги подкаталогов и так далее, пока не перечислит все файлы. Правда, чтобы просмотреть действительно все файлы в директории, нужно войти как администратор (root), потому что некоторые каталоги могут не давать прав доступа рядовому пользователю.

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

Команда grep найдет нужные вам строки, если вы зададите образец для поиска:

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

Среди команд-фильтров самая употребительная, без сомнения, grep. Она применяется везде, где нужно выбрать искомое из большого объема данных. Скажем, просмотреть все, что касается USB в выводе команды dmesg:

Это только начало списка строк, выведенных командой grep -i usb , я не привожу его полностью из экономии места. Опция -i приказывает команде grep не замечать разницы между заглавными и строчными буквами.

Любой системный администратор часто пользуется командой ps. С опциями -e и -f она выводит все процессы, текущие в системе в полной форме (подробно). Процессов этих весьма много, поэтому я не привожу полный вывод команды:

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

С таким коротким списком уже легче работать. (Обратите внимание на последнюю строчку, там представлен сам запущенный нами процесс grep hald ).

Другие распространенные команды-фильтры

Кроме команды grep (или вместе с ней) часто употребляются следующие команды:

sort - сортирует строки по алфавиту или порядку номеров

wc - подсчитывает количество строк, слов, байт или символов в тексте

tr - заменяет одни символы другими

sed - позволяет редактировать текст прямо из командной строки, даже не видя его.

cut - вырезает из текста нужные куски и выдает их на стандартный вывод

head/tail - позволяют ограничить просмотр первыми несколькими строками (head - голова), либо последними несколькими строками (tail - хвост).

В этот список я включил только несколько команд-фильтров, освоив которые, можно вдоволь насладиться составлением самых замысловатых программных каналов.

Сложные программные каналы

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

Примечание: Символ (\) используется для объединения всех шести строк в одну командную строку.

Команда первая: wget получает содержимое HTML web страницы.

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

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

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

Команда пятая: sort сортирует список "слов" в алфавитном порядке, а с опцией -u удаляет дубликаты.

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

Немного истории

Идею программных каналов и значок вертикальной черты как их обозначение придумал Douglas McIlroy, один из авторов ранних командных оболочек. Он обратил внимание на то, сколько времени уходит на обработку вывода одной программы в качестве ввода другой. Его идеи были внедрены в жизнь, когда в 1973 Ken Thompson добавил программные каналы в операционную систему Юникс. Идея была со временем позаимствована другими ОС, такими как DOS, OS/2, Microsoft Windows, и BeOS, часто даже с тем же обозначением.

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

Английское название именованного канала - named pipe или FIFO (File In, File Out - файл пришел, файл ушел). Именованные каналы служат в основном для межпроцессного взаимодействия, когда различные процессы в системе обмениваются информацией. Тема это сложная и большая, заслуживающая отдельной статьи. Поэтому в данной работе я только вкратце коснусь ее.

В отличие от анонимного программного канала, автоматически создаваемого шеллом, именованный канал обладает именем, и создается явно при помощи команд mknod или mkfifo. Создадим именованный канал fifo1:

Теперь запустим процесс, обращающийся к данному каналу:

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

Чтобы наполнить именной канал содержимым, нужно чтобы к нему обратился второй процесс. Для этого мы должны открыть вторую консоль и запустить какую-либо команду, передающую данные в файл fifo1. Например:

Немедленно в первой консоли сработает команда grep:

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

и получить тот же результат.

Этот пример я привел лишь для демонстрации создания и работы именованного канала. Другое дело, когда именованные каналы создаются самими процессами для обмена информацией друг с другом. Но повторюсь, что тема эта непростая и в данной статье рассматриваться не будет.

Favorite

Добавить в избранное

Главное меню » Linux » Что такое каналы (pipe) в Linux? Как работает перенаправление каналов?

Что такое каналы (pipe) в Linux? Как работает перенаправление каналов?

В озможно, вы слишком много раз использовали синтаксис cmd0 | cmd1 | cmd2, подобный вашему терминалу.

Вы, вероятно, также знаете, что такое перенаправление канала, которое используется для перенаправления вывода одной команды в качестве ввода для следующей команды.

Но знаете ли вы, что под ним? Как на самом деле работает перенаправление каналов?

Не беспокойтесь, потому что сегодня мы демистифицируем каналы Unix, чтобы в следующий раз, когда вы пойдете на свидание с этими причудливыми вертикальными полосами, вы точно знали, что происходит.

Примечание. Мы использовали термин Unix в некоторых местах, потому что концепция каналов (как и многие другие вещи в Linux) происходит от Unix.

Каналы в Linux: общая идея

Вот что вы повсюду увидите относительно «что такое каналы в Unix?»:

Это общее объяснение, которое дают все. Мы хотим проникнуть глубже. Давайте перефразируем предыдущую строку более техническим языком, убрав абстракции:

Намного лучше. Удаление абстракции сделало его намного чище и точнее. Вы можете посмотреть на следующую схему, чтобы понять, как работает pipe.

Имейте в виду: Pipe перенаправляет стандартный вывод на стандартный ввод, но не как аргумент команды

Очень важно понять, что конвейер передает команду stdout другой команде stdin, но не как аргумент команды. Мы объясним это на примере.

Если вы используете команду cat без аргументов, по умолчанию будет выполняться чтение из stdin. Вот пример:

Здесь мы использовали cat без передачи файлов, поэтому по умолчанию stdin. Затем мы написали строку, а затем использовал Ctrl + d, чтобы сообщить, что закончили писать (Ctrl + d подразумевает EOF или конец файла). Как только мы закончили писать, cat прочитал stdin и написал эту строку в stdout.

Теперь рассмотрим следующую команду:

Фактически, мы создали файл с именем hey и поместили в него некоторый контент.

Типы каналов в Linux

В Linux есть два типа каналов:

  • Безымянный канал, также называемый анонимным.
  • Именованные каналы

Каналы без названия

Без названия каналы, как следует из названия, не имеют имени. Они создаются на лету вашей оболочкой Unix всякий раз, когда вы используете символ |.

Когда люди говорят о каналах в Linux, они обычно говорят об этом. Они полезны, потому что вам, как конечному пользователю, не нужно ничего отслеживать. Ваша оболочка справится со всем этим.

Именованные каналы

Этот немного отличается. Именованные каналы действительно присутствуют в файловой системе. Они существуют как обычный файл. Вы можете создать именованный файл, используя следующую команду:

Это создаст файл с именем «pipe». Выполните следующую команду:

Обратите внимание на «p» в начале, это означает, что файл является каналом. Теперь воспользуемся этим каналом.

Вы заметите, что echo еще не вернули нам терминал. Откройте новый терминал и попробуйте прочитать из этого файла.

Обе эти команды завершили свое выполнение одновременно.

Это одно из фундаментальных различий между обычным файлом и именованным каналом. В канал ничего не записывается, пока какой-либо другой процесс не прочитает его.

Зачем использовать именованные каналы? Вот список того, почему вы хотите использовать именованные каналы

Именованные каналы не занимают память на диске

Если вы выполните a du -s pipe, вы увидите, что он не занимает места. Это потому, что именованные каналы похожи на конечные точки для чтения и записи из буфера памяти и в него. Все, что записывается в именованный канал, фактически сохраняется во временном буфере памяти, который сбрасывается, когда операция чтения выполняется из другого процесса.

Сниженный ввод-вывод

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

Связь между двумя очень разными процессами

Выходные данные события можно мгновенно и очень эффективно получить из другого процесса с помощью именованных каналов. Поскольку чтение и запись происходят одновременно, время ожидания практически равно нулю.

Понимание каналов более низкого уровня [для опытных пользователей и разработчиков]

В следующем разделе речь идет о каналах на более глубоком уровне с фактическими реализациями. Этот раздел требует от вас базового понимания:

  • Как работает программа на C
  • Что такое системные вызовы
  • Что такое процессы
  • Что такое файловые дескрипторы

Мы не будем вдаваться в подробности примеров. Речь идет только о «каналах». Для большинства пользователей Linux этот раздел не нужен.

Рассмотрим следующий пример программы:

Читать Лучшие приложения для решения математических уравнений для Linux

В строке 16 мы создали безымянный канал, используя функцию pipe(). Первое, что следует заметить, это то, что мы передали массив целых чисел со знаком длиной 2.

Именованный канал ничем не отличается. С именованным каналом вместо двух файловых дескрипторов вы получаете имя файла, которое можно открыть из любого процесса и работать с ним, как с любым другим файлом, учитывая при этом характеристики канала.

Вот пример программы, которая делает то же самое, что и предыдущая программа, но вместо анонимного канала создает именованный канал.

Здесь мы использовали системный вызов mknod для создания именованного канала. Как вы можете видеть, хотя мы удалили канал по завершении, вы вполне можете оставить его и легко использовать для связи между различными программами, просто открыв и записав в файл с именем «npipe» в моем случае.

Вам также не придется создавать два разных канала для двусторонней связи, как в случае с анонимными каналами.

Вот образец Makefile, как и было обещано. Поместите его в тот же каталог, что и предыдущие программы, с именами «pipe.c» и «fifo.c» соответственно.

Вот так. Это действительно все, что есть в каналах Unix.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Взаимодействие процессов - это обмен данными между двумя процессами. В Linux существует несколько способов взаимодействия процессов. В этой статье мы в основном представляем самый простой метод-канал взаимодействия процессов.

Способы коммуникации процесса

Единственный способ обмена информацией между процессами - передача открытых файлов.

Труба

Канал - это одна из старейших и наиболее простых форм системного IPC, все системы Linux предоставляют такой механизм связи. Однако у конвейера есть два следующих ограничения:

  • Это полудуплексный режим, то есть данные по каналу могут передаваться только в одном направлении. Если требуется двусторонняя связь, между двумя процессами должны быть установлены два канала;
  • Каналы могут использоваться только между двумя процессами с общим предком; -

Механизм реализации трубы

Канал - это буфер, которым управляет ядро, один конец которого подключен к выходу процесса, а другой конец подключен к входу процесса. Буфер конвейера не обязательно должен быть большим, он спроектирован как кольцевая структура данных, когда два процесса завершаются, жизненный цикл конвейера также завершается.

Создание конвейера

Канал создается путем вызова функции конвейера.

(pipe1)

Он возвращает два файловых дескриптора по выходному параметру fd,fd [0] открыт для чтения, fd [1] открыт для записи, Выходные данные fd [1] являются входными данными fd [0]. Когда канал создается успешно, функция канала возвращает 0. Если создание не удается, она возвращает -1. Связь между fd [0] и fd [1] показана на рисунке ниже:

Как общаться по трубе


Выше мы установили конвейер в одном процессе, но на самом деле конвейер в одном процессе бесполезен. Обычно процесс сначала вызывает функцию конвейера для создания канала, а затем вызывает функцию fork (). Функция fork изменяет родительский процесс. Соответствующая структура данных наследуется дочернему процессу, так что дочерний процессДескриптор файлаFd [0] и fd [1] в таблице указывают на файл конвейера, на который указывает родительский процесс, так что связь между двумя процессами может быть реализована. Вышеупомянутый процесс выглядит следующим образом:

Связанные правила использования трубопроводной связи

Для конвейера от дочернего процесса к родительскому процессу (запись дочернего процесса, чтение родительского процесса) родительский процесс закрывает fd [1], дочерний процесс закрывает fd [0], когда часть конвейера закрывается (закрывается на основе вышеизложенного Один конец трубы) Работают следующие два правила:

  1. При чтении канала, сегмент записи которого был закрыт, после того, как все данные были прочитаны,чтение возвращает 0(чтение возвращает 0, чтобы указать, что конец файла был прочитан);
    Проверим:


Программа позволяет дочернему процессу записать строку три раза, а затем закрывает дочерний процесс fd [1], то есть закрывает конец записи канала, и не закрывает fd [0] родительского процесса, то есть конец чтения канала.

  1. Если вы пишете в канал, конец чтения которого закрыт, он будетГенерируйте соответствующие сигналыПроцесс записи сегмента завершается. Если сигнал игнорируется или сигнал захватывается и возвращается обработчиком, команда write вернет -1, а errno будет установлено значениеEPIPE;
    Проверим:


Цель кода такова: мы позволяем концу записи (дочернему процессу) всегда записывать строку msg, а конец чтения (родительский процесс) читает три раза, а затем закрывает fd [0] родительского процесса, так что дочерний процесс записывает все время , А родительский процесс не читает. Результаты приведены ниже:

Мы обнаружили, что после того, как родительский процесс закрыл fd [0], дочерний процесс былПрервано ненормально, Из кода выхода и кода сигнала выхода дочернего процесса мы обнаружили, что это сигнал 13 (SIGPIPE) Завершается, поэтому запись в канал, закрытый на конце чтения, не соответствует действительности для PIPE. Операционная система отправит процессу завершения записи после закрытия конца чтенияSIGPIPEВызвать завершение процесса.

  1. Если концы для чтения и записи канала не закрыты, но конец канала для записи больше не записывает данные в канал. В это время, если в конвейере нет данных, процесс чтения будет заблокирован до тех пор, пока в конвейере не появятся данные, прежде чем считывать данные и возвращаться.
  2. Если файловый дескриптор, указывающий на конец чтения канала, не закрыт, а тот, который удерживает конец чтения канала, не читает данные из канала, то есть процесс, записывающий данные в канал. Если канал заполнен, а затем записывает данные в канал, напишите снова Вызывает блокировку процесса до тех пор, пока в канале не останется места, прежде чем он продолжит запись данных в канал и возврат.

емкость трубы

Мы можем пройти* man 7 pipe*; Для запроса пропускной способности трубопроводаpipe_capacity


Теперь давайте обсудим каждый Оператор один за другим.

1. && Оператор (AND оператор)

Синтаксис использования оператора AND:

Оператор выполнит вторую команду только в том случае, если команда 1 успешно выполнена.

Теперь рассмотрим синтаксис выше.

Здесь команда 2 будет выполняться только в том случае, если команда 1 выполнена успешно. Например :

Здесь, как вы можете видеть ниже, первая команда успешно завершена, тогда выполняется вторая команда df -h.

Теперь давайте проверим оператор AND по-другому.

Здесь я не буду выполнять первую команду и посмотрю, выполняется ли вторая команда или нет.

Как вы можете видеть выше, первая команда не работает, поэтому вторая команда не выполняется.

2. OR Оператор (||)

Синтаксис использования оператора OR:

OR полностью противоположна оператору &&.

OR выполнит вторую команду только в том случае, если первая команда провалится.

Теперь давайте приведем пример:

Как вы можете видеть выше, вторая команда выполнена, то есть «df -h», когда первая команда не удалась.

3. Оператор AND & OR (&& и ||)

Комбинация оператора && и OR (||) довольно интересна и даст вам хороший результат, если вы используете его правильно.

Давайте приведем пример, чтобы вы получили больше представлений по этому поводу:

4. Оператор PIPE (|)

Например, вы хотите проверить все текущие системные процессы, используя команду ps -ef. но поскольку список процессов настолько длинный, что его нельзя охватить на одном экране.

В этом случае вы можете использовать фильтр с командой more.

5. Оператор точка с запятой (;)

Оператор точка с запятой выполняет несколько команд одновременно последовательно, как упоминалось, и обеспечивает вывод без зависимости от успеха и отказа других команд, таких как && и OR (||).

Посмотрите пример ниже:

6. Амперсанд Оператор (&)

Вы можете использовать этот оператор для одновременного выполнения нескольких команд.

Вы также можете выполнять несколько команд с помощью оператора Ampersand. См. Команду ниже.

Читайте также: