FreeSource : СтатьяКлассическийUnixWay

назад (заготовки статей)

Классический UNIX-way или «компьютер для профессионала»

Введение для читающих разрабатываемую версию статьи


Основные принципы


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

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

there's more than one way to do it

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

Простой пример — в первый же день, когда я столкнулся с Linux, мне было нужно определить суммарный размер файлов в дереве каталогов. Я не знал тогда команды du (оценивающей место на диске, занимаемое файлом или группой файлов), однако я знал две базовых для многих задач в Linux команды — find (поиск файлов в подкаталогах по заданому условию и вывод их названий) и xargs (выполнить указаную команду, передавая в качестве параметров вводимые данные). И кроме того, я помнил про утилиту wc, подсчитывающей количество строк, слов и символов во вводимом файле, а также cat, выводящую указаные файлы. И сделал так:

find -type f -print0 | xargs -0 cat | wc

Сложная с виду команда имеет крайне простое устройство, и была придумана мной, новичком в Linux, за десятки секунд (время понадобилось, чтобы уточнить параметры команд find и xargs).

С помощью команды find я нашёл и вывел список файлов в текущем каталоге и всех
подкаталогах, xargs передала этот список команде cat, которая и передала
содержимое этих файлов на вход команде wc. Та, в свою очередь, всё посчитала
и вывела результат.

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

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


Приведённый выше пример, кроме того, иллюстрирует и другой подход: «Одна задача — одна
программа». Этот подход является самым важным в UNIX-мире. Именно он даёт
возможность сделать одновременно простую, эффективную, надёжную и функциональную
рабочую среду.

Чем сложнее задача, тем сложнее написать для неё качественное
решение. Чем проще задача — тем проще решение, для очень простых задач
легче всего написать компактные, эффективные, надёжные, удобные средства. Но сложную задачу обычно можно «разложить» на множество простых.

В UNIX-системах есть достаточно обширный и, что немаловажно, проверенный опытом набор «кирпичиков», или утилит – программ, решающих простые задачи. Соединяя их, можно выполнить почти любые действия. UNIX предлагает стандартные способы такого соединения, которые работают практически с любыми из утилит.

Основными такими утилитами являются grep/egrep/fgrep (фильтрующие поток
данных выполняя поиск по регулярным выражениям), sort (сортировка), cat
(вывод файла или группы файлов), colrm (вырезание отдельных колонок),
column, paste, sed, uniq, less. Ну и самая главная программа, это программа
“man”, выводящая документацию по любой другой программе.

Всё есть текст


Главное, что необходимо для конструирования решения сложных задач с помощью маленьких утилит – стандартный подход к обмену данными между программами. В качестве такого подхода принято использовать “plain text” (простой текст).

Основное преимущество именно “plain text” — возможность на любом этапе обработки оператору посмотреть самостоятельно промежуточные данные, а также простота обработки текста с помощью утилит sed/awk/col*/grep/sort/uniq и.т.д.

Существуют даже графические форматы (pbm и его вариации) где либо заголовок, либо вообще все данные идут в текстом виде. Этот подход крайне удобен для обработки данных скриптовыми языками (которые, в отличии от языков вроде Си, обычно имеют достаточно удобные и мощный средства работы со строками). Реально сейчас практически все виды данных, разве что кроме звуковых (мне неизвестно почему) имеют “plain text” вариант исполнения, хотя бы для заголовков.

Его преимущество – возможность работы с утилитой как непосредственно с командной строки, так и с данными из файлов или в «цепочке» из других утилит без всяких изменений.

Таким образом, можно сначала разобраться в работе утилит «вручную», а потом – составить «цепочку» для нужной задачи. И наоборот – если «цепочка» почему-то работает не так, как нужно, можно выполнить только её часть и посмотреть результаты на экране (или в «пробном» файле).

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

pipes (потоки, трубы)


pipes это основной метод связи программ в UNIX-like ОС друг с другом.
Каждый раз, когда мы используем символ '|' в командной строке (shell),
мы создаём трубу (pipe), которая соединяет стандартный вывод (stdout)
одной программы со стандартным вводом (stdin) другой программы. Таким образом
когда одна программы выдаёт что-либо, мы можешь это либо увидеть на экране,
либо перенаправить на ввод другой программы. Например такой командой может
быть “less”, которая отображает полученую через stdin информацию, с
возможностью прокрутки вперёд и назад, а также поиска (more в DOS является
сильно упрощённым функциональным аналогом).

Также мы всегда можем перенаправить stdout программы в файл, или взять
данные из файла:

sort < unsorted.txt > sorted.txt

Всё есть файл


Одна из самый удивительных концпеций. Например вы можете сделать так:

cat bootsect.bin > /dev/fd0

и таким образом запишите образ загрузочного сектора прямо на дискету.

Или вы можете сделать так:

dd if=/dev/cdrom of=cd.iso

и таким образом вы сделаете образ компакт-диска (последнюю сессию, только
данные), который пригоден для записи с помощью утилиты cdrecord.

Вы можете сделать так:

dd if=/dev/hda bs=512 count=1 of=mbr.bin

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

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

Ещё хорошие примеры — в Linux принято монтировать виртуальную файловую
систему /proc, которая даёт доступ ко многим ресурсам системы. Например:

cat /proc/cmdline — опции переданые ядру при загрузке
cat /proc/cpuinfo — подробная информация об установленых в системе процессорах
cat /proc/pci — информация об установленых PCI-устройствах

Таким образом можно даже менять настройки системы, например:

echo using_dma:1 > /proc/ide/hda/settings

разрешит использование DMA для primary master IDE устройства.

Скрипты


Пользователю не так уж часто нужно решать относительно простые задачи, вроде
вывода на экран отфильтрованого списка файлов. Ему необходимо объединять утилиты в более сложные задачи. И для этого существует
ещё одна основа UNIX-мира — glue languages (язык-клей, чаще всего используется
термин «скриптовые языки», “script languages”).
Они предназначены для склеивания
множество блоков и создания единой программы, выполняющей какую-либо задачу.

bash (Bourne Again SHell)

Самый используемый язык в UNIX-like ОС. Чаще всего пользователи в работают именно с ним, сами того не зная.
Дело в том, что bash это чаще всего используемая оболочка («shell»), и любая последовательность команд, вводимым
с клавиатуры, может быть записана как скрипт, который можно потом повторно использовать. Для пользователей DOS будет яснее, если я скажу что это аналог COMMAND.COM, только функционально гораздо богаче. (Пользователи OS/2 обычно знают что такое COMMAND.COM, но для них персонально я скажу, что это аналогично CMD.EXE).

Из моего предыдущего примера я мог сделать скрипт вида:

#!/bin/bash
find $1 -type f -print0 | xargs -0 cat | wc

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

Собственно, одно из самых полезных использований скриптов — автоматизация часто выполняемых задач. Как говорится «настоящий программист никогда не станет делать одно и то же два раза — вместо второго он предпочтёт написать программу», скрипты же дают возможность «написать программу» даже человеку без специального образования. (Особенно это верно для языка bash, поскольку изучить его весьма просто – и любой, кто работает в командной строке bash, постепенно осваивает этот язык).

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

Язык bash обычно достаточен для «склеивания утилит» в чистом виде и минимальной логики, хотя он и обладает достаточно большими возможностями, обычно используют другие скриптовые языки, которые более пригодны для сложной обработки данных. Эти скриптовые языки могут быть сложнее в изучении. Но они обладают и немалыми возможностями, позволяя ополнять недостающую логику и создавать достаточно мощные программы. В частности, именно на скриптовых языках обычно реализуют логику работы сколь-либо сложных Web-сайтов (простой пример – форумы), а также системы управления (CMSContent Managment System), без которой создание и особенно поддержка сайта с со сколь-либо сложным дизайном и количеством страниц больше двух (обо мне и моей любимой кошке) превращается в настоящий ад.

Основное отличие «скриптовых» языков от «больших» (из которых преимущественно используются C и C++), наряду с относительной простотой – в отсутствии необходимости компиляции, переработки компьютером исходного текста в исполняемый файл. Поэтому программы на них куда проще запускать.

Perl (Practical Extraction and Report Language)


Основное его предназначение явно видно из названия – «Практический язык для извлечения [данных] и [создания] отчётов». Поэтому он стал одним из самых распространённых средств программирования в Web (как для Web-серверов, так и для утилит сбора и анализа информации из Web). Единственным (и самым серьёзным) его недостатком является его... гибкость, позволяющая легко написать код, который потом будет иметь мало шансов понять даже сам Larry Wall (автор этого языка).

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

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

Людям, не имеющим серьёзного опыта программирования в Perl, я рекомендовал бы не тратить время на изучение этого языка (за исключением необходимости писать сколь-либо серьёзные скрипты для Web — там он пока вне конкуренции).

Python

Быстро развивающийся сейчас объектно-ориентированый язык. Судя по тенденциям имеет все шансы отвоевать значительную часть ниши Perl'а. Одним из самых известных продуктов, написаных на Python, является Zope — мощная объектно-ориентированая среда разработки Web-приложений.

В отличие от Perl, Python имеет немалые средства для поддержания читаемости кода. Это делает его гораздо удобнее и практичнее в применении. Тот, кто знает, что такое вернуться к написанному полгода назад скрипту на Perl, задаваться вопросом «Ну и какой идиот это написал?», видеть ответ в копирайтах «Ты сам» и приниматься переписывать заново, ибо это может быть проще чем разобраться со старым, меня поймёт.

Этот язык имеет только один недостаток — сейчас он крайне быстро развивается, не всегда сохраняя совместимость «сверху вниз» – т.е. программы, написанные для старых версий, могут не запуститься на новых. Основная проблема при этом – использование в Web; весьма неприятно было бы обнаружить, что сайт со скриптами на Python перестал работать, поскольку администратор Web-сервера обновил версию Python.

Tcl (Tool Command Language)

Этот язык известен в первую очередь благодаря великолепной библиотеке Tk, позволяющей очень легко создавать сложнейшие графические интерфейсы. Кроме того, Tcl отличается потрясающей простотой и гибкостью (я не видел языков с более простой грамматикой, при этом обладающих такой же простотой как написания, так и чтения кода, и гибкостью, позволяющей использовать его в решении широкого круга задач).

Библиотеку Tk можно использовать и из программ на других скриптовых языках, в частности Perl и Python. Кроме того, Tcl очень легко прикручивается к программам на Си (в свою очередь на Си легко писать модули для Tcl). Но для создания интерфейсов связка Tcl / Tk обычно наиболее удобна из-за оригинального синтаксиса этого языка (совмещающего простоту с функциональностью).

Приятно видеть, что в магазинах появилась литература по Tcl — хоть пока и откровенно слабенькая, но достаточная для начинающего пользователя (в том числе и Windows-пользователя, ибо код на Tcl отлично переносим).

Пользователю я бы рекомендовал изучать именно этот язык, как только возможностей связки bash+sed+awk для него окажется мало. Сочетание компактности, производительности, удобства написания кода, удобства чтения и редактирования существующего кода и простоты содания интерфейса делают связку Tcl / Tk наиболее пригодным средством для широкого круга пользовательских задач.

Языки-утилиты для обработки построчных данных

Наряду с мощными скриптовыми языками, описанными више, существуют более «узкоспециализированные» языки для обработки построчных данных. Они очень удобны при построении «цепочек», т.к. позволяют достаточно гибко преобразовать текстовые данные. Также при помощи них нередко удобно автоматически редактировать конфигурационные файлы (ведь практически вся конфигурация Unix также хранится в виде текстов).

Наиболее распространены sed и awk.

sed — язык, имитирующий работу простейшего редактора (команды вида «удалить строку», «добавить строку», «выполнить замену по регулярному выражению», и.т.д.)

awk — каждая строка проходит через последовательность условий; для каждого условия, которому эта строка удовлетворяет, выполняется соответствующий код. Кроме того каждая строка разбирается на поля (разделитель полей можно выбрать), что позволяет использовать его для автоматизированой обработки таблиц.

Редактирование текста


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

Поэтому достаточно мощные редакторы разработаны уже давно. Они заметно отличаются от привычных пользователю «текстовых процессоров»; их сложнее освоить, однако для многих задач они оказываются существенно мощнее. При этом скорость их работы заметно выше, а требования к компьютеру — меньше.

Есть два классических средства для работы с текстом: vi и emacs. Каждое из них претерпело массу изменений по сравнению с оригинальными версиями, и, несмотря на свой возраст, являются современными средствами, умеющие, в том числе, корректно работать в графическом режиме (в том числе встраиваясь в другие приложения как gvim).

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

vi


Там где есть UNIX, там есть vi. Если в UNIX'е нет vi, то вам только кажется,
что перед вами UNIX (или кажется, что нет vi, даже в Mac OS X vi есть).
Самый простой редактор, отличающийся в первую очередь тем, что его легко
использовать даже через терминал по низкоскоростным модемным соединениям.

vim


VIM (Vi IMproved) — как ясно из названия, расширенный vi. Благодаря расширениям
он стал одним из самых гибких по возможностям редакторов в мире. Он поддерживает
множество различных подходов к редактированию текста, позволяет создавать
и использовать как клавиатурные макросы (можно полностью перенастроить
клавиатуру так, как вам надо), так и скрипты на множестве различных языков
программирования. Имеет такие средства как folding (сокрытие вложенных элементов структуры текста, например,
«тел» (реализаций) отдельных функций, когда идёт просмотр программы в целом), навигацию по программному
коду и т.д.

Его возможности делают его незаменимым при редактировании сложных документов и программного кода (не считая Emacs, который может всё, без преувеличений).

Emacs


Emacs был бы хорошей операционной системой, если бы в нём был приличный текстовый редактор — известная шутка об этом редакторе. Как и в каждой шутке, в этом высказывании есть доля шутки, а всё остальное — правда. В данном случае правда заключается в том, что Emacs даже не операционная система — он скорее виртуальная машина, а точнее Lisp-машина, а если точнее, используется некоторое подможество языка Lisp — elisp (Lisp — язык, который когда-то планировалось использовать как язык для разработки систем искуственного интеллекта, но не удалось, однако для многих других задач он оказался на удивление гибким и удобным средством). Это делает возможности Emacs практически безграничными. Среди компьютерщиков есть шутки в стиле "'программа ... всё может, разве что кофе варить не умеет", ответом на эту шутку стал модуль управления кофеваркой для Emacs, так что Emacs действительно может всё — даже варить кофе.

Существует, например, Gnus — почтовый и NNTP клиент выполненый как набор lisp-скриптов для emacs, также есть IRC-клиенты, средства навигации по коду, и даже некое подобие нотного редактора.

Emacs является одним из самых известных программных продуктов, написаным
лидером движения Free Software — Ричардом Столлманом.

Прикладные задачи

Подготовка документов


Один из распространённых подходов в UNIX (и, естественно, в UNIX-like ОС) является «Ты это просил? Получи!», вместо «Что ты видешь, то и получишь (WYSIWYG)".

При создании текстов и сложных документов наилучшим примером такого подхода является система подготовки текстов Te X, написаная Дональдом Кнутом изначально для вёрстки своих книг (с большим количеством формул), и являющаяся ныне стандартом де-факто в некоторых математических и физических изданиях.

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

По сути Te X – не просто «средство вёрстки» и даже не язык разметки; это полноценный язык программирования, описание которого (пусть и самое поверхностное) не может уместиться в одной статье.

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

TODO: кто может подсказать что нужно сказать про Meta Font?
TODO: какие ссылки есть смысл поставить на книги и статьи по latex для начинающих?
TODO: написать кто такой Дональд Кнут (для тех кто этого не знает, а таких среди неспециалистов масса)

3D графика


Есть миф, что в Linux нет средств для подготовки 3D-графики. Я промолчу про такой коммерческий пакет как Maya – на нём был был сделан фильм Final Fantasy, и он отличается от модной у нас 3DStudioMax, как Боинг от дельтаплана. Также я умолчу о том, что он есть и под другие ОС (под Windows предлагается даже бесплатная «персональная версия»), а также о том, что он и под них тоже написан в классическом UNIX-стиле — мухи отдельно, котлеты отдельно, в смысле интерфейс отдельно, логика отдельно, то есть движок для рендеринга есть отдельное консольное приложение.

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

Pov Ray


Pov Ray это классика 3D-графики. Это «всего лишь» движок, выполняющий рендеринг картинки. На входе 3D сцена, на выходе картинка. Рендеринг выполняется методом «трассировки лучей» (самый качественный, но самый требовательный к ресурсам методом), потому он в своё время и не получил широкого распространения.

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

Blender


Коммерческий 3D-редактор, который был выкуплен сообществом за 100'000$ и отдан под GPL. По функциональности он несколько слабее современных 3D Studio Max, однако имеет возможность подключать скрипты на Python, может использовать из командной строки для рендеринга уже готовых сцен, а также может использоваться как внешний движок для формирования и рендеринга сцен. При всём при этом он весьма компактен по размеру.

2D графика


TODO: gnuplot
TODO: uniq
TODO: grep
TODO: sort
TODO: less
TODO: man
TODO: ссылки на интерфейсы к Blender

P.S. Эта статья пишется специально для сборника «Дары Свободы — Свободное программное обеспечение: прошлое, настоящее, будущее»
http://www.livejournal.com/users/ramendik/10142.html

назад (заготовки статей)