На эту тему в Сети можно найти несметное количество статей и обсуждений, не удивлюсь если Вам уже доводилось читать что-либо подобное в прошлом или может быть работать в одной из множества операционных систем, разработанных с использованием этой идеологии. За этим словосочетанием скрывается целая философия разработки программного обеспечения, начавшая свое развитие в середине 90-х годов прошлого века и воплощенная в огромном количестве операционных систем и в еще большем количестве opensource проектов. В этом тексте я хочу поведать Вам свой взгляд на эту философию с двух точек зрения: программиста и пользователя.

Наиболее точно охарактеризовать то, о чем пойдет речь можно лишь процитировав одного из основателей традиций Unix и разработчика технологии под названием "Unix pipes" - Douglas'а Mcllroy'а:

"This is the Unix philosophy: - Write programs that do one thing and do it well. - Write programs to work together. - Write programs to handle text streams, because that is a universal interface."

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

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

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

Закончив лирическое отступление, хочется взглянуть на нашу философию с точки зрения программиста.

Взгляд с точки зрения программиста

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

Как же это выглядит?

Одна задача - одна программа

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

Подобное множество программ решающих элементарные задачи делает количество способов решения какой-либо комплексной задачи стремящимся к бесконечности, ведь при наличии стандартизованного интерфейса комбинировать программы можно в любой последовательности. Для расширения возможностей такого рода комбинирования используются различные скриптовые языки, которых существует достаточно много, наиболее распространенным из которых являются bash скрипты, основанные на командах одноименной оболочки командной строки, используемой по-умолчанию во всех (хотя возможно стоило не использовать громких слов и написать "в большинстве") дистрибутивах Linux.

Unix pipes

Этот механизм является основным способом реализации столько раз упоминавшегося выше интерфейса между элементарными программами. Реализация его поддержки является как раз второй задачей, которая ставится перед программистом, идущим по пути Unix. С использованием большинства языков программирования она является тривиальной, особенно это справедливо для C.

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

Взгляд с точки зрения пользователя

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

У каждой элементарной программы, соответствующей этой идеологии, должен быть входной и выходной стандартные текстовые потоки - stdin и stdout соответственно. Механизм unix pipes позволяет перенаправлять эти потоки любой программы произвольным образом с помощью трех простых операторов: |, > и <. Первый из них - | перенаправляет stdout команды слева от него в stdin команды справа, а > и < предназначены для перенаправление потоков в/из файлы по схожему принципу.

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

  • cat - вывод содержимого указанного первым параметром файла в stdout (по умолчанию stdout в большинстве программ направляется в консоль)
  • less - постраничный вывод текста, полученного в stdin в stdout (переключение страниц и некоторые другие функции производятся с клавиатуры, возможны и другие варианты использования, но они нам не нужны)
  • grep - построчная фильтрация текста, полученного в stdin, вывод только строк, содержащих текст, указанный первым аргументом, и вывод результата в stdout.

Начнем с примера, позволяющего прочитать постранично любой файл:

cat readme.txt | less

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

cat readme.txt | grep unix > readme.txt

Этот пример должен был бы удалить из файла все строки, где нет слова "unix". Маленькое замечание: при использовании такого перенаправления, перед началом передачи данных файл обнуляется. В этом и заключается ошибка данного примера: файл очищается до того, как поток данных успел пройти через фильтрацию grep, что приводит к просто очистке файла. Если же Вам все же нужен отфильтрованный список строк - стоит разместить в другом файле (которым можно было бы подменить исходный при необходимости), просто поменяв его название:

cat readme.txt | grep unix > meread.txt

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

cat readme.txt | grep unix >> readme.txt

В unix-like системах есть еще одна интересная особенность, косвенно связанная с этим механизмом: все устройства являются файлами и соответственно, прикреплены к файловой системе, для них выделена отдельная директория, по традиции называемая /dev. Работа с ними также ведется на тех же правах что и с обычными файлами, например набрав в консоли:

cat readme.txt > /dev/dsp

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

Подводим итоги

С точки зрения простого пользователя использование opensource решений, построенных на базе философии unix, является как минимум нетривиальной задачей - ведь от него требуется как минимум понимание насколько мощная и гибкая система попала ему/ей в руки. Отсутствие единственного верного способа решения той или иной задачи ставит большинство людей попросту в тупик, у них начинают разбегаться глаза от десятков тысяч программ, доступа к которым есть у всех пользователей unix-like операционных систем, с помощью набора простой волшебной команды в консоли, состоящей не более чем из трех-четырех слов.

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

06 января 2008 |  Иван Блинков  |  Linux