|
| ||||||||||||
| ||||||||||||
Введение в POSIX'ивизм(C) Алексей Федорчук, 2005Опубликовано на сайте LinuxCenter Глава 12. Истина - в командахНам уже приходилось говорить о командах, а некоторые даже использовать на практике. Потому что командный интерфейс (интерфейс командной строки, Command Line Interface, он же CLI) - это очередная вечная истина POSIX-мира, постижение которой позволит пользователю взаимодействовать с системой. Содержание
Введение в CLIКак говорилось в предыдущей главе, POSIX-мир не обделен визуальными, или графическими (по нашему, по бразильскому, - Гуёвым) интерфейсами. Однако роль CLI от этого меньше не становится. Ибо CLI а) исконен в Unix'ах, б) универсален, и в) представляет собой базу, для которой GUI всякого рода являют лишь оболочку. Поясню последнюю мысль. Всякое действие в POSIX-системе может быть выполнено прямой командной директивой (что это - станет понятно чуть позже). И его же можно осуществить путем манипулирования объектами. Например, копирование файлов выполняется соответствующей командой - А теперь пора перейти собственно к командам. Интерфейс пользователя с POSIX-системой обеспечивается в большинстве случаев классом программ, именуемых командными интерпретаторами, командными процессорами, командными оболочками или по простому Как легко догадаться по одному из определений, кроме предоставления пользовательского интерфейса, шеллы выполняют и еще одну функцию - служат интерпретаторами собственных языков программирования. Сам по себе второй момент для нас сейчас не существенен. Однако именно на нем основывается классификация шеллов. Ибо программ таких существует изрядное множество, которое можно разделить на две группы, обычно именуемые - Bourne-shell совместимые и C-shell совместимые. В силу ряда причин в качестве стандарта POSIX принята одна из оболочек первой группы - так называемый POSIX-шелл. Правда, он представляет собой чистую абстракцию, однако большинство используемых в Unix'ах оболочек декларируют ту или иную степень совместимости с ним. Собственно описанию шеллов будет посвящена отдельная глава. В главе же настоящей я попробую совместить роскошное - понимание принципов командного интерфейса, - с необходимым - изучением базовых команд. А заодно - и с полезным. то есть описанием особенностей того самого мифического POSIX-шелла, наиболее последовательно воплощенных в стандартных оболочках Free- и NetBSD (т.н. Командная строкаОсновой командного интерфейса является командная строка, начинающаяся с приглашения для ввода (далее обозначается милым сердцу россиянина символом длинного зеленого друга - Командная директива (или просто команда) - основная единица, посредством которой пользователь взаимодействует с шеллом. Она образуется по определенным правилам, именуемым синтаксисом. Синтаксис командной директивы определяется, в первую очередь, языком, принятым в данной командной оболочке. Кроме того, некоторые команды (не очень многочисленные, но весьма употребимые) имеют собственный, нестандартный синтаксис. Однако в целом базовые правила построения команд имеют много общего - по крайней мере, в POSIX-совместимом семействе. И именно эти базовые правила будут предметом данного раздела. Синтаксические особенности отдельных нестандартных команд будут оговариваться по ходу изложения. Итак, командная директива образуется:
Очевидно, что имя команды является обязательным компонентом, тогда как опции и аргументы могут и отсутствовать (или подразумеваться в неявном виде по умолчанию). Еще один непременный компонент командной директивы - это специальный невидимый символ конца строки: именно его ввод отправляет команду на исполнение. В обыденной жизни этот символ вводится нажатием и отпусканием клавиши Enter. Почему обычно и говорят: для исполнения команды нажмите клавишу Enter. Тот же эффект, как правило, достигается комбинацией клавиш Control+M. Конца командной строки, знаменующего исполнения команды, мы на экране не видим. Однако важно, что это - такой же символ, как и любой другой (хотя и имеющий специальное значение). Это знание нам понадобится, когда речь дойдет до специальных символов вообще (и даже немного раньше). В подавляющем большинстве случаев опции (или их последовательности) задаются непосредственно за именем команды, а аргумент (или группа аргументов) команду завершает, хотя это правило имеет некоторые исключения. Вне зависимости от порядка опций и аргументов, принятых для данной команды, интерпретация их осуществляется слева направо. Команды, опции и аргументы обязательно разделяются между собой пробелами. Кроме того, опции обычно предваряются (без пробела) символом дефиса или двойного дефиса. Впрочем, немногочисленные (но весьма употребимые) команды могут использоваться с опциями без всяких предваряющих символов. Как уже говорилось, имя команды определяет выполняемые ею функции. Существуют команды, встроенные в оболочку, то есть не имеющие запускающих их исполняемых файлов, и команды внешние. В последнем случае имя команды однозначно указывает на имя исполняемого файла программы, выполняемой при отдаче соответствующей директивы. Часто встроенные и внешние команды одного назначения имеют одинаковые имена - в этом случае по некоторым причинам, которые станут ясными через раздел, обычно предпочтительно использование встроенных команд - впрочем, они и вызываются в первую очередь. Некоторые команды могут выступать под несколькими именами. Это связано с тем, что исторически в различных Unix-системах команды, исполнявшие одинаковые функции, могли получать разные названия. В каждой конкретной системе обычно используется только одна из таких команд-дублеров. Но при этом имена дублирующих команд также могут присутствовать в системе - для совместимости. Не следует думать, что это две различные программы одного назначения: как правило, такая синонимичность команд реализуется посредством механизма ссылок или псевдонимов ( Иногда команда, вызванная через имя своего синонима, может отличаться по своей функциональности от самой же себя, вызванной под родным именем. В этом случае говорят о эмуляции одной команды другой. Типичный пример - командная оболочка Для правильного применения команд, конечно же, нужно знать их имена и назначение. Однако нас никто не заставляет напрягать пальцы вводом имени команды полностью. Потому что нам на помощь приходит великий принцип автодополнения: для любой команды достаточно ввести первые несколько ее символов - и нажать клавишу табуляции (Tab). И, если введенных буковок достаточно для однозначной идентификации, полное имя команды волшебным образом возникнет в строке. Если же наш ввод допускает альтернативы продолжения имени - все они высветятся на экране (сразу или после повторного нажатия на табулятор), и из них можно будет выбрать подходящую. Поясню на примере. Создание пустого файла выполняется командой $ to <Tab> toc2cue toc2mp3 toe top touch из которого мы и выберем подходящее. В данном случае достаточно набора еще одной буковки Большинство употребимых команд POSIX-систем - коротки и мнемонически прозрачны. И может показаться. что не такое уж это облегчение - заменить ввод двух-трех символов нажатием табулятора (а то еще и неоднократным). Однако, когда речь дойдет до аргументов команд - тут вся мощь автодополнения станет явной. И еще маленькое отступление. Автодополнение - стандартная возможность ОпцииКак уже говорилось, указания имени достаточно для выполнения некоторых команд. Типичный пример - команда $ ls back/ Desktop/ Mail/ OpenOffice.org1.1.2/ soft/ work/ bin/ docs/ mnt/ other/ tmp/ daemon/ lena/ music/ signature wallpapers/ Исполнение же многих других команд невозможно без указания опций и (или) аргументов. Для них в ответ на ввод одного ее имени часто следует не сообщение об ошибке (или не только оно), но и краткая справка по использованию команды. Например, в ответ на ввод команды для создания каталогов usage: mkdir [-pv] [-m mode] directory ... Для одних опций достаточно факта их присутствия в командой директиве, другие же требуют указания их значений (даваемых после опции через пробел или знак равенства). В приведенном примере команды А вот опция Многие опции имеют две формы - краткую, односимвольную, и полную, или многосимвольную, Некоторые же опции могут быть даны только в многосимвольной форме. Общее правило здесь таково: если одного символа достаточно для однозначного определения опции, могут употребляться обе формы в качестве равноправных. Однако поскольку количество символов латинского алфавита ограниченно (а человеческая фантазия, конструирующая опции - безгранична), при большом количестве опций одной команды некоторые из них приходится делать исключительно многосимвольными. Продемонстрирую это на примере опций все той же команды -m, --mode=MODE установить код доступа (как в chmod) -p, --parents не выдавать ошибок, если существует, создавать родительские каталоги, если необходимо -v, --verbose печатать сообщение о каждом созданном каталоге --help показать помощь и выйти --version вывести информацию о версии и выйти Очевидно, что для опции Раз уж зашла речь об опциях Опять-таки, из того же примера видно, что опции в односимвольной форме предваряются единичным символом дефиса и могут быть даны единым блоком, без пробелов: $ mkdir -vpm 777 dir/subdir При этом, естественно, опция, требующая указания значений, ставится последней, и ее значение отделяется пробелом. Опции же в многосимвольной форме требуют предварения удвоенным дефисом, обязательно должны разделяться пробелами и значения их, если таковые требуются, присваиваются через символ равенства (по научному он называется еще оператором присваивания): $ mkdir --parents --mode=777 dir/subdir Загадочные семерки после опции Опции команды именуются также флагами (реже ключами) или параметрами. Однозначной трактовки этих терминов нет. Однако обычно под флагами подразумеваются опции, не требующие указания значений. Термин параметр же применяется к опции, такового требующей, и объединяет опцию и ее значение. Правда, мне встречалось определение параметра как совокупности опций и аргументов, но я буду придерживаться приведенных определений. Опции определяют условия выполнения команды. Выше был приведен пример команды Различные же опции команды $ ls -a она обеспечивает вывод списка имен всех файлов, включенных в текущий каталог, включая скрытые файлы вида $ ls -l дается вывод списка имен файлов в "длинном" формате (отсюда название опции drwxr-xr-x 5 alv users 136 2004-08-04 10:58 back/ drwxr-xr-x 2 alv users 232 2004-07-29 13:00 bin/ drwxr-xr-x 19 root root 720 2004-08-04 14:45 daemon/ drwx------ 3 alv users 136 2004-07-18 14:00 Desktop/ drwxr-xr-x 13 alv users 328 2004-07-26 10:40 docs/ drwxr-xr-x 2 alv users 176 2004-07-21 03:43 lena/ drwxr-xr-x 17 alv users 1736 2004-08-04 17:51 Mail/ drwxr-xr-x 2 alv users 48 2004-07-20 22:24 mnt/ drwxr-xr-x 18 alv users 552 2004-08-05 09:03 music/ drwxr-xr-x 5 alv users 416 2004-08-04 14:17 OpenOffice.org1.1.2/ drwxr-xr-x 5 alv users 144 2004-07-22 01:22 other/ -rw-r--r-- 1 alv users 71 2004-07-22 12:20 signature drwxr-xr-x 11 alv users 272 2004-08-04 16:42 soft/ drwxr-xr-x 3 alv users 360 2004-08-06 08:29 tmp/ drwxr-xr-x 2 alv users 344 2004-07-20 22:22 wallpapers/ drwxr-xr-x 14 alv users 376 2005-10-11 06:43 work/ Форма $ ls -F позволяет получить список файлов с символьным различением файлов различных типов. Например, имя каталога будет выглядеть как back/ Desktop/ Mail/ OpenOffice.org1.1.2/ soft/ work/ bin/ docs/ mnt/ other/ tmp/ daemon/ lena/ music/ signature wallpapers/ А форма $ ls --color=auto представит те же типы файлов в списке в различной цветовой гамме (впрочем, при некоторых условиях; и, добавлю, Я столь подробно остановился на команде Порядок опций, если их приводится более одной, для большинства команд не существенен. Хотя, например, для команды $ tar cf filename.tar dir и $ tar -cf filename.tar dir абсолютно равноценны: и та, и другая создает единый архивный файл Особый смысл имеет символ удвоенного дефиса АргументыОднако тема стандартного ввода (а равно и вывода) - у нас еще на горизонте. А пока мы подобрались к понятию аргументов командной директивы. Аргументами определяется, как правило, объект (или объекты) действия команды. В большинстве случаев в качестве аргументов команд выступают имена файлов и (или) пути к ним. Выше говорилось, что при отсутствии аргументов команда $ ls /usr/local/bin Для правильного построения аргументов команды требуется рассмотрение еще одного понятия - пути к файлу. Путь - это точное позиционирование файла в файловой системе относительно ее корня (обозначаемого символом прямого слэша - Так, если пользователь находится в своем домашнем каталоге (абсолютный путь к нему обычно выглядит как $ ls ../../usr/local/bin Первый путь в аргументе команды Пути в аргументах команд могут быть весьма длинными. Например, чтобы просмотреть доступные раскладки клавиатуры, в Linux нужно дать команду примерно следующего вида: $ ls /usr/share/kbd/keymaps/i386/qwerty И читатель вправе спросить - неужели мне все это вводить вручную? Отнюдь - отвечу я ему. Потому что автодополнение, о котором упоминалось по ходу разговора об именах команд, действует также для путей в их аргументах. И в данном случае обязательный ввод будет выглядеть следующим образом: $ ls /u Все недостающие символы будут добавлены автоматически. А такая оболочка, как $ ls /u/s/k/k/i/q которая нажатием табулятора сама развернется в точный полный путь. Большинство команд допускает указание не одного, а нескольких (и даже очень многих) аргументов. Так, единой директивой вида $ cp file1 file2 ... fileN dir можно скопировать (команда Маленькое отступление. Упоминание команды $ cp dir1 dir2 Как вы думаете, что получится в результате? Правильно, сообщение о невозможности выполнения этой операции - примерно в таком виде: cp: omitting directory 'dir1' поскольку команда Маленькое уточнение: вполне возможно, что в дистрибутиве, который имеется в вашем распоряжении, проходит и копирование каталогов просто через Вообще рекурсия (то есть определение некоего выражения через самого себя) - очень важное понятие в Unix, пронизывающее происходящие от нее системы насквозь. И послужившие даже базой для своеобразного хакерского юмора. Вспомним GNU, что, согласно авторскому определению, означает - GNU is Not Unix. Однако сейчас для нас важно только то, что рекурсия применима практически ко всем файловым операциям, позволяя распространить действие одной командной директивы не только на файлы данного каталога, но и на все вложенные подкаталоги и их содержимое. Однако вернемся к аргументам. Действие некоторых команд неоднозначно в зависимости от аргументов, к которым она применяется. Например, команда $ mv filename1 filename2 то следствием будет переименование $ mv filename dir то результатом будет перемещение $ mv file1 ... fileN dir1 ... dirM dirN в каталог Кое-что об исключенияхИтак, типичная форма POSIX-команды в обобщенном виде выглядит следующим образом: $ command -[options] [arguments] Из этого правила выбиваются немногочисленные, но весьма полезные и часто используемые команды. Однако и для таких команд с нестандартным синтаксисом устанавливаются те же компоненты - имя, опции, аргументы, хотя по ряду причин (в том числе исторических) порядок их может меняться. Это можно проиллюстрировать на примере полезнейшей команды $ find dir -option1 value -option2 [value] Здесь
$ find ~/ -name *.tar -exec tar xf {} \;
требует отыскать в домашнем каталоге ( В последнем примере имеется несколько символов, смысл которых может показаться непонятным. Надеюсь, он прояснится достаточно скоро - в параграфе о регулярных выражениях. ПсевдонимыВернемся на минуту к команде Отнюдь - ответил бы граф, стуча манжетами о подоконник. Потому что этот вопрос задавали себе многие поколения не только пользователей, но и разработчиков. И ответили на него просто - введением понятия псевдонима команды ( Что это такое? В большинстве случаев - просто некоторое условное имя, подменяющее определенную команду с теми ее опциями, которые мы используем чаще всего. Причем, что характерно, псевдоним команды может совпадать с ее именем. То есть, например, - набирая просто Устанавливаются псевдонимы очень просто - одноименной командой $ alias ls='ls -F --color=auto' В BSD-реализации команда ls не понимает опции--color=auto, и потому здесь аналогом приведенного псевдонима будет: $ alias ls='ls -FG' В обоих случаях следует обратить внимание на два момента: а) на то, что имя псевдонима совпадает с именем команды (что отнюдь не препятствует создания псевдонима типа Маленькое отступление: приведенная форма определения псевдонима действительна для всех shell-совместимых оболочек. В оболочках же семейства C-shell синтаксис команды будет иным: $ alias ls ls -FG То есть разделителем между именем псевдонима, командой и ее опциями выступают символы пробела (или табуляции). А заключение значения псевдонима в кавычки потребуется только в том случае, если "псевдонимичная" командная конструкция включает более одного пробела (например, сопровождается несколькими опциями или аргументами). Таким образом мы можем наделать себе псевдонимов на все случаи жизни. В разумных пределах, конечно - иначе вместо упрощения жизни мы создадим себе необходимость запоминания множество невнятных сочетаний символов. Однако на наиболее важных (и обычно определяемых) псевдонимах я остановлюсь. Вспомним команды типа Разумеется, иногда так и нужно, например, при резервном копировании старые версии файлов и должны быть заменены их более свежими вариантами. Однако такое приемлемо далеко не всегда. И потому в большинстве команд, связанных с необратимыми изменениями файловой системы, предусматривается специальная опция - $ cp file1 file2 cp: overwrite file2'? И пользователь может решить, нужно ли ему затирать существующий файл, ответив Так вот, дабы не держать в голове необходимость опции $ alias cp='cp -i'; $ alias mv='mv -i'; $ alias rm='rm -i' Все это, конечно, очень благородно, заметит внимательный читатель. Но что, если мне заведомо известно, что сотни, а то и тысячи файлов целевого каталога должны быть именно переписаны новыми своими версиями (как тут не вспомнить про случай с резервным копированием)? Что же, сидеть и, как дурак, жать на клавишу Y? Не обязательно. Потому что все команды рассматриваемого класса имеют еще опцию $ alias cpf='cp -f' Правда, предварительно нужно убедиться, что в системе нет уже команды с именем, совпадающим с именем псевдонима - иначе эффект может быть весьма неожиданным (впрочем, это относится ко всем псевдонимам, не совпадающим с именами подменяемых команд). Есть и другой способ обойти опции, установленные для команды-псевдонима: просто отменить псевдоним. Что делается командой обратного значения $ unalias alias_name То есть дав директиву $ unalias cp мы вернем команде копирования ее первозданный смысл. Ну а узнать, какие псевдонимы у нас определены в данный момент, и каковы их значения, еще проще: команда $ alias без опций и аргументов выведет полный их список: la='ls -A' less='less -M' li='ls -ial' ll='ls -l' ls='ls -F --color=auto' и так далее. Когда я сказан о пользовании псевдонимами ныне, и присно, и вовек, - то был не совсем точен. Ныне, то есть в текущем сеансе пользователя - да, они работают. Однако после рестарта системы (или просто после выхода из данного экземпляра командной оболочки) они исчезнут без следа. Чтобы заданные псевдонимы увековечить, их нужно прописать в конфигурационном файле пользовательского шелла. Но этим мы займемся впоследствии - в главе 15. А пока обратимся к переменным. ПеременныеПеременные играют для аргументов команд примерно такую же роль, что и псевдонимы - для команд. То есть избавляют от необходимости мрачного ввода повторяющихся последовательностей символов. Конечно, это - далеко не единственное (а может быть, и не главное) назначение переменных, однако на данном этапе для нас наиболее существенное. Что такое переменная? Ответ просто - некоторое имя, которому присвоено некоторое значение. Не очень понятно? - Согласен. Но, возможно, станет яснее в дальнейшем. Имена переменных в принципе могут быть любыми, хотя некоторые ограничения также существуют. Я уже вскользь упоминал о переменных в разделе про пользователей. В частности, там, помнится, фигурировали переменные Таких встроенных переменных довольно много. И одна из первых по значению - переменная $ echo $PATH Обратим внимание на то, что в качества аргумента команды выступает не просто имя переменной, а оно же, но предваренное символом доллара. Который в данном случае никакого отношения к приглашению командной строки не имеет, а предписывает команде /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin Тем временем вернемся к переменной $ cd /home/alv достаточно набрать $ cd $HOME и он в своих владениях. Может показаться, что экономия - грошовая (тем паче, что перейти в собственный каталог пользователь может просто командой Кроме переменных, предопределенных в шелле, пользователю предоставляется почти полная свобода в определении переменных собственных. И вот тут-то и наступает ему обещанное облегчение при наборе аргументов команд. Предположим, что у нас имеется глубоко вложенный подкаталог с данными, постоянно требующимися в работе. Чисто условно примем, что путь к нему - следующий: /home/alv/data/all.my.works/geology/plate-tectonics Весьма удручающе для набора, даже если исправно работать табулятором для автодополнения, не так ли? Прекрасно, упрощаем себе жизнь определением переменной: $ plate=/home/alv/data/all.my.works/geology/plate-tectonics Дело в шляпе, Теперь, если нам нужно просмотреть состав этого каталога, достаточно будет команды $ ls $plate А вызвать из него любой файл для редактирования можно так: $ joe $plate/filename Подобно псевдонимам, переменные, определенные таким образом (то есть просто в командной строке), имеют силу только в текущем сеансе работы - по выходе из оболочки они утрачиваются. Для того, чтобы они действовали перманентно, переменные должны быть прописаны в конфигурационном файле пользовательского шелла. Однако, в отличие от псевдонимов, и этого оказывается не всегда достаточно. Ибо переменная, определенная посредством $ NAME=Value работает не просто только в текущем сеансе - но еще и только в конкретном экземпляре шелла. Почему и называется переменной оболочки - shell variable. Звучит это. быть может, пока не очень понятно. Однако в разделе о процессах мы уже видели, что практически любое действие в шелле - запуск команды или программы, например, - начинается с того, что оболочка, в которой это действие совершается, запускает новый экземпляр самой себя - дочерний шелл, или, как иногда говорят, субшелл. Так вот, этот самый субшелл не наследует переменные родительской оболочки. И в итоге запущенная из командной строки программа ничего не будет знать, например, о путях к исполняемым файлам. Что автоматически ведет к невозможности запуска из нее команд просто по имени, без указания точного пути. Чтобы избежать такой неприятной ситуации, было придумано понятие переменных окружения, или переменных среды - environment variable. Это - те переменные, которые наследуются от родительского шелла всеми дочерними программами. И чтобы сделать их таковыми, переменные следует экспортировать. Как? Командой $ NAME=Value а затем применить к ней команду $ export NAME А можно сделать это в один прием: $ export NAME=Value Второй способ применяется, если нужно определить и экспортировать одну переменную. Если же за раз определяется несколько переменных: $ NAME1=Value1; $ NAME2=Value2; ...; $ NAMEN=ValueN то проще прибегнуть к первому способу, так как команда $ export NAME1 NAME2 ... NAMEN Оговорка: такой способ задания переменных действует только в POSIX-совместимых шеллах. В оболочках семейства set EDITOR=joe А чтобы та же самая переменная имела силу для всего окружения (то есть была бы переменной среди) потребуется другая команда: setenv EDITOR=joe Впрочем, традиционно имена переменных окружения задаются в верхнем регистре, переменных оболочки - в нижнем. Каждая из этих команда, данная без аргументов, выведет список определенных переменных оболочки и окружения соответственно. А для вывода значений абсолютно всех переменных есть специальная встроенная команда - printenv. Навигация и редактированиеИмя команды, ее опции и аргументы образуют т.н. командные "слова". В качестве словоразделителей выступают пробелы. Кроме того, как разделители "слов" интерпретируется ряд специальных символов - прямой слэш ( В некоторых случаях имеет смысл различать "большое слово" и "малое". Первое включает в себя словоразделитель (например, пробел), в качестве же второго интерпретируются символы, лежащие между словоразделителями. Понятно выразился? Если не очень - надеюсь, станет яснее при рассмотрении примеров. Подчеркнем, что командное "слово" прямо не соотносится ни с опциями, ни с аргументами команды. Введение этого понятия призвано просто облегчить навигацию в командной строке и ее редактирование. Ибо одно из великих достижений командного интерфейса POSIX-систем, заценить которое могут в полной мере только те, кто застал времена "черного DOS'а", - это возможность перемещения внутри командной строки и внесения необходимых изменений в имя команды, ее опции и аргументы. Делается это различными способами. Самый привычный и, казалось бы, очевидный способ - использование клавиш перемещения курсора Оказывается - есть чего, и самый очевидный способ навигации и редактирования оказывается не самым эффективным. Для начала заметим, что в общем случае привычные клавиши перемещения курсора и редактирования в POSIX-системах не обязаны работать также, как они делают это в DOS/Windows. Это зависит от многих причин, в том числе и исторических. Ведь POSIX-системы по определению предназначены работать на любых практически машинах (в том числе и на тех, клавиатуры которых клавиш управления курсором просто не имели). Однако это не главное - в большинстве Linux-дистрибутивов командная оболочка по умолчанию настраивается так, чтобы пользователь при желании мог использовать привычные ему клавиши. Однако тут-то и оказывается, что плюс к этому оболочка предоставляет ему много более эффективную систему навигации по командной строке и ее редактирования. И это - система управляющих последовательностей, так называемых keybindings. То есть сочетания специальных клавиш, именуемых управляющими, с обычными алфавитно-цифровыми. Основные управляющиеся клавиши, которые используются в таких последовательностях (и имеются на клавиатурах почти любых машин - как говорят в таких случаях, в любых типах терминалов) - это клавиши Control и Meta. Пардон - возразит внимательный читатель, - сколько я ни долблю по клавишам моей PC'шки, но клавиши Meta не замечал. Возражение принято, но: на PC-клавиатурах функции Meta выполняют либо а) нажатие и отпускание клавиши Escape, либо б) нажатие и удерживание клавиши Alt. Впрочем, к этой теме я еще вернусь. А пока достаточно нескольких простых рецептов, практически универсальных для любых командных оболочек в терминалах любых типов. Рецепт первый: большая часть управляющих последовательностей состоит из сочетания клавиши Control и алфавитно-цифрового символа. Под сочетанием (или комбинацией, для чего я уже употреблял ранее символ плюс) понимается то, что, удерживая нажатой клавишу Control, мы одновременно нажимаем и какую-нибудь литерную или цифровую. Так, действие клавишной комбинации Control+F (от Forward - в большинстве случаев регистр алфавитной клавиши управляющей последовательности значения не имеет) эквивалентно нажатию клавиши Right - это перемещение на один символ вправо, комбинации Control+B (от Back) - нажатию Left (перемещение на один символ влево). Комбинации Control+A и Control+E действуют аналогично Home и End, перемещая курсор в начало и конец командной строки, соответственно, Ну а с помощью комбинаций Control+D и Control+H можно удалить единичный символ в позиции курсора или перед ней (также, как и клавишами Delete и Backspace, соответственно). Предвижу резонный вопрос: а какие достоинства в комбинации клавиш Control+Что_то по сравнению с элементарными End или Left? Конечно, одно достоинство - очевидно: при массовом вводе команд (а также, забегая вперед, замечу - и любых иных наборов символов, от исходных текстов до романов), при использовании keybindings руки не отрываются от основной (алфавитно-цифровой) части клавиатуры. И в итоге, по приобретении некоторого минимального навыка, дело движется ну гораздо быстрее. Обосновать тестами не могу (тут какая-нибудь физиометрия понадобится), но не верящим - предлагаю попробовать. Главное же преимущество клавиатурных последовательностей перед стандартными навигационными клавишами - много более широкая их функциональность. Я не случайно начал этот параграф с упоминания командных "слов" - это, наряду с единичными символами, также навигационные (и, добавлю, редакционные) единицы командной строки. То есть управляющие последовательности позволяют при навигации и редактировании оперировать не только единичными символами, но и целыми словами. Например, комбинация Meta+F смещает курсор на одно "слово" вперед, та же Meta в сочетании с B - на одно слово назад, и так далее. Прошу обратить внимание: действие алфавитной клавиши в комбинации с Meta сходно по смыслу ее сочетанию с клавишей Control, но как бы "усилено": последовательность Meta+D уничтожает не символ в позиции курсора, как это было бы для D в сочетании с Control, а все командное "слово". Рассматривать ключевые последовательности подробно здесь я не буду: детали их действия зависят от командной оболочки и ее настроек. Отмечу только два существенных обстоятельства. Первое: keybindings предоставляют пользователю полный комплекс приемов для любых действий в командной строке - вплоть до преобразования регистров уже введенных символов и "слов" (из нижнего в верхний и наоборот), "перетасовки" символов в команде или ее аргументах, и так далее. И не только в командной строке - большинство популярных в POSIX-мире текстовых редакторов, от простых И второе - действие ключевых последовательностей, как правило. не зависит не только от типа терминала и физического устройства клавиатуры, но и от ее раскладки - при переключении на кириллицу они будут работать столь же справно, как и в латинице. История командВозможности навигации и редактирования строки особенно ярко проявляются в сочетании с другой замечательной особенностью, предоставляемой командными оболочками - доступом к истории команд. То есть: раз введенная в строке команда не уходит в небытие после исполнения, а помещается в специальный буфер памяти (который, как и все в Unix'ах, именуется весьма незатейливо - буфер истории команд; однако смешивать его с экранным буфером консоли, о котором говорилось в предыдущей главе, не следует - это вещи совершенно разные). Откуда команда (со всеми ее опциями и аргументами) может быть извлечена для повторного использования. Или - для редактирования и исполнения в новой реинкарнации. Буфер истории команд сохраняется в течении всего сеанса работы. Однако в большинстве случаев командные оболочки настраиваются так, что по выходе из сеанса буфер истории сохраняется в специальном файле в домашнем каталоге пользователя, и таким образом его содержимое оказывается доступным при следующем запуске шелла. Имя этого файла может быть различным в разных оболочках, но обычно включает компонент Конечно, не совсем вечная. И размер буфера истории команд, и количество строк в файле истории - величины конечные. Так что, если установленный предел превышен, то старые команды вытесняются более новыми. Однако и величину буфера, и количество строк в файле истории можно установить любыми (в разумных пределах - не знаю, существует ли принципиальное ограничение на них, за исключением объема памяти и дискового пространства). А если учесть, что и из буфера, и из памяти с помощью соответствующих настроек (со временем я расскажу, каких) можно исключить дубликаты и еще кое-какой мусор - то мое заявление о вечной жизни команд не выглядит столь уж преувеличенным. Универсальное средство доступа к буферу истории команд - специальная команда, встроенная во все шеллы, таковой поддерживающие - В качестве опции можно указать желаемое количество одновременно выведенных команд. Например, директива $ history -2 выведет две последние команды из буфера истории вместе с их номерами: 1023 joe shell.html 1024 less ~/.zshrc Любая из команд в буфере истории может быть повторно запущена на исполнение. Для этого достаточно набрать в командной строке символ $ !1023 для приведенного выше примера повторно откроет файл Другой способ доступа к командам из буфера истории - комбинации клавиш Control+P и Control+N, служащие для последовательного его просмотра (как бы "пролистывания") назад и, соответственно, вперед (разумеется, если есть куда). Они дублируются клавишами управления курсором Up и Down (назад и вперед, соответственно). Кроме того, последовательности Meta+< и Meta+> обеспечивают переход к первой и последней команде в буфере истории. Любая извлеченная (с помощью стрелок или управляющими последовательностями) из буфера истории в текущую строку команда может быть повторно запущена на исполнение - нажатием клавиши Enter или дублирующей ее комбинацией Control+M. Причем предварительно ее можно отредактировать - изменить опции, или аргументы, - точно так же, как и только что введенную. Во всех современных "развитых" шеллах предусмотрены средства поиска команды в буфере истории - простым перебором (обычно Meta+P - назад и Meta+N - вперед). Впрочем, не смотря на громкое название, это ничем практически не отличается от обычного пролистывания исторического списка курсорными стрелками. Что при обширной истории команд может быть весьма утомительным. И потому для ее облегчения предусмотрена такая интересная возможность, как наращиваемый поиск (incremental search) нужной команды в буфере истории по одному (или нескольким) из составляющих ее символов. Выполняется инкрементный поиск так: после нажатия (при пустой командной строке) клавишной комбинации Control+R появляется предложение ввести алфавитный символ (или - последовательность символов произвольной длины), заведомо входящий в состав требуемой команды: $ bck-i-search: _ Ввод такого символа выведет последнюю из команд, его содержащих. При этом введенный символ будет отмечен знаком курсора. Он не обязан входить в имя команды, но может быть составляющим ее опций или аргументов (имени файла или пути к нему, например). Следующее нажатие Control+R зафиксирует курсор на предыдущем символе, в пределах этой же или более ранней по списку команды, и т.д. Однако вместо этого в строке поиска можно вводить дополнительные символы, детализирующие условия поиска команды (или - ее опций и аргументов). Процедуру поиска можно продолжать вплоть до достижения требуемого результата - то есть нахождения той команды, которая нужна именно сейчас. Нажатие клавиши Enter в любой из этих моментов запускает найденную (то есть помещенную в командную строку) команду на исполнение, с завершением поиска. Поиск обрывается также и нажатием комбинации Control+C. Перед запуском найденная команда может быть отредактирована стандартными средствами - с использованием управляющих последовательностей. Некоторые шеллы допускают чрезвычайно изощренные средства обращения с буфером истории команд. Например, в командной оболочке Регулярные выраженияНе зря я, видно, вспомнил во вступлении к этой главе о семи смертных грехах. Потому что одному из этих грехов все пользователи-POSIX'ивисты должны быть привержены в обязательном порядке. И грех этот - леность, можно сказать, показатель профессиональной пригодности линуксоида. В соответствие со своей леностью разработчики POSIX-систем придумывают способы, как бы им минимизировать свои усилия. А пользователи из лени изощряются в применении этих приемов на практике. В частности - в том, как свести к минимуму набор в командной строке. Собственно говоря, этой цели служили почти все приемы, описанные выше. Осталось осветить немногое. А именно - регулярные выражения, реализуемые с помощью т.н. специальных символов (или метасимволов). Элементарная, и весьма частая, в духе школьных, задача: из каталога $ cp dir1/* dir2 Чуть усложним условия: к копированию из $ cp dir1/*html dir2 Обращаем внимание: в Linux, в отличие от DOS/Windows, шаблон Однако тут можно вспомнить, что html-документы могут иметь и расширение $ cp dir1/*htm? dir2 то она гарантированно охватит все возможные маски html-документов. Вроде все хорошо. Однако нет: из каталога
$ cp path/{file1,file2,file3} dir2
И приведет к единоразовому копированию всех трех файлов в каталог Группировка аргументов может быть сколь угодно глубоко вложенной. Так, команда
$ mkdir -p dir1/{dir11/{dir111,dir112},dir12/{dir121,dir122}}
в один заход создаст трехуровневую структуру каталогов внутри текущего - если только не забыть про опцию И еще несколько примеров. Регулярное выражение для диапазона - то есть вида Последние примеры регулярных выражений могут показаться надуманными. Однако представим. что в том же каталоге $ cp dir1/*[^html] dir2 И в каталоге Из приведенных примеров можно видеть, что метасимволы, образующие регулярные выражения, интерпретируются командной оболочкой особым образом, не так, как обычные алфавитно-цифровые символы, составляющие, скажем, имена файлов. В то же время мы уже видели (в главе 8), что собственно POSIX-системы накладывают на имена файлов очень мало ограничений. И в принципе система не запретит вам создать файл с именем, содержащим метасимволы. Другое дело, что работать с таким образом именованными файлами может быть сложно - командная оболочка будет пытаться интерпретировать их в соответствии с правилами для регулярных выражений. Конечно, использовать метасимволы в именах файлов весьма не рекомендуется. Однако а) возможны элементарные ошибки при наборе, и б) файлы, полученные при обмене с другими операционными системами (сами знаете. какими), могут иметь довольно непривычный (и, я даже сказал бы, неприличный) вид. Вспомним, что MS Word в качестве имени файла спокойно берет первую фразу документа. А если это - вопрос? И тогда завершающий имя символ Маленькое отступление. Командные директивы, с многочисленными их опциями, особенно в полной форме, и аргументами могут оказаться весьма длинными, не укладывающимися в пределы экранной строки. Правда, обычно командная оболочка по умолчанию настраивается с разрешением так называемого word wrapping'а (то есть переноса "слов" команды без обрыва строки - последнее, как мы помним, достигается нажатием клавиши Enter или комбинации Control+M и приводит к немедленному исполнению введенной команды; если ввод ее не окончен - последует сообщение об ошибке). Однако перенос "слов" при этом происходит, как бог на душу положит. И в результате командная директива теряет читабельность и становится сложной для понимания. Тут-то и приходит на помощь понятие экранирования, упомянутое абзацем выше. Знак экранирования - обратный слэш ( Возвращаемся к экранированию обратным слэшем. Действие его распространяется только на непосредственно следующий за ним символ. Если символы, могущие быть воспринятые как специальные, идут подряд, каждый из них должен предваряться обратным слэшем. У обратного слэша есть еще одна интересная особенность - я назвал бы ее инвертированием специального значения символов. Для примера: некая последовательность цифр (например, Есть и экраны, распространяемые на все, что заключено внутри них. Это - кавычки, двойные и одинарные: большая часть символов между ними утрачивает свое специальное значение, Buono Parte, но не все. В двойных кавычках сохраняют специальное значение метасимволы $ echo "с вас, уважаемый, \$500" Еще одно широко применяемое использование двойных кавычек - экранирование пробелов, предотвращающих разбиение аргументов команды на отдельные "слова". Правда, в случае с командой Из сказанного понятно, почему двойные кавычки именуются еще неполными, или не строгими - они все же допускают внутри себя использование символов со специальными значениями. В противоположность им, кавычки одинарные носят имя строгих, или полных. Потому что между ними утрачивают специальное значение все метасимволы, кроме их самих - в том числе и символ единичного экранирования. В итоге они используются там, где гарантированно требуется отсутствие специальных символов. Если вы помните, мы применили строгие кавычки при установке псевдонимов. Они же часто оказываются обязательными при определении переменных. Завершая тему экранирования, осталось сказать только об обратных кавычках. Их функция очень узка: они служат для экранирования команд. То есть, скажем, команда $ echo date в полном соответствие со своим именем, просто выведет нам собственный аргумент: date Однако если аргумент команды закрыть обратными кавычками, то $ echo `date` Втр Дек 16 11:45:12 MSK 2003 Если вспомнить, что обратные кавычки сохраняют свое специальное значение внутри кавычек двойных, становится ясной польза от их применения: они незаменимы в тех случаях, когда требуется вывод результатов работы одной команды внутри другой. К как в нашем примере с выводом даты, если его (вывод) следует включить в некое выдаваемое командой Конечно, в описанном случае добиться той же цели можно было бы гораздо легче - просто командой $ echo "На момент `date` в системе \ зарегистрированы `who`" Ответом на что будет сообщение, подобное тому, что часто можно наблюдать на главной странице многих сайтов: На момент Втр Дек 16 12:11:36 MSK 2003 \ в системе зарегистрированы alv lis А теперь последнее, чем и закроем тему регулярных выражений вообще. В этом разделе рассматривалось использование метасимволов в командной оболочке (конкретно, в данном случае. в Командные конструкцииПора вернуться к генеральной линии моего рассказа - основам командного интерфейса. Надеюсь, из предшествующего изложения читателю стало ясно, что подавляющее большинство команд в POSIX-системах очень просты по сути и предназначены для выполнения какого-либо одного элементарного действия. То есть команда $ rm -Rf * Для тех, кто не испытал этого волнительного ощущения, поясню: результатом будет полное и безвозвратное уничтожение всех файлов от текущего каталога вниз (включая подкаталоги любой степени вложенности). Собственно, разделение любой задачи на серию элементарных операций - это и есть основной принцип работы в POSIX-системах, тот самый пресловутый Unix-way, о котором столько говорят его приверженцы (в которых с некоторых пор числит себя и автор этих строк). Однако вслед за этапом решительного размежевания (эх, неистребимы в памяти нашего поколения слова товарища Ленина) должен наступить этап объединения, как за анализом явления следует синтез эмпирических данных. И целям такого объединения служат командные конструкции. Командные конструкции - очень важный компонент интерфейса командной строки. Они позволяют объединять несколько команд воедино и выполнять различные команды последовательно или параллельно. Для этого служат специальные символы - операторы: фонового режима, объединения, перенаправления и конвейеризации. Простейшая командная конструкция - это выполнение команды в фоновом режиме, что вызывается вводом символа амперсанда после списка опций и (или аргументов): $ command [options] [arguments] & В $ command1 & command2 & ... & commandN В результате все команды, кроме указанной последней, будут выполняться в фоновом режиме. Существуют и конструкции для последовательного выполнения команд. Так, если ряд команд разделен в строке символом точки с запятой ( $ command1 ; command2 ; ... ; commandN то сначала будет выполнена команда $ command1 $ command2 ... и так далее. При этом первая команда может, например, копировать файлы, вторая - осуществлять поиск, третья - выполнять сортировку, или другие действия. Очевидно, что в общем случае выполнение последующей команды не зависит от результатов работы предшествующей. Однако возможна ситуация, когда результаты предыдущей команды из такой конструкции используются в команде последующей. В этом случае ошибка исполнения любой составляющей команды, кроме последней, делает невозможным продолжение работы всей конструкции. Что само по себе было бы еще полбеды - однако в некоторых ситуациях исполнение последующей команды возможно только при условии успешного завершения предыдущей. Характерный пример - сборка программы из ее исходных текстов, включающая три стадии - конфигурирование, собственно компиляцию и установку собранных компонентов. Что выполняется (несколько забегу вперед) последовательностью из трех команд: $ ./configure $ make $ make install Ясно, что если конфигурирование завершилось ошибкой, то компиляция начаться не сможет и, соответственно, потом нечего будет устанавливать. И потому объединение их в последовательную конструкцию вида $ ./configure ; make ; make install может оказаться нецелесообразным. Однако для предотвращения таких ситуаций в конструкции из взаимосвязанных команд существует другой оператор, обозначаемый удвоенным символом амперсанда - $ ./configure && make && make install На практике обе приведенные в качестве примера конструкции дадут один и тот же результат. Однако в ряде иных случаев различие между этими конструкциями может быть существенным. Впрочем, предусмотрена и командная конструкция, в которой последующей команде предписано исполняться в том и только в том случае, если предыдущая команда завершилась неудачно. Она имеет вид $ command1 || command2 и может служить, в частности, для вывода сообщений об ошибках. Конечно, можно найти ему и другие применения (как, впрочем, и оператору Следующая командная конструкция - это так называемое перенаправление ввода/вывода. Тут тоже нам придется несколько забежать вперед, однако перенаправление - слишком практически важный прием, чтобы отложить его рассмотрение его до выяснения прочих обстоятельство. И потому вкратце: любая команда получает данные для своей работы (например, список опций и аргументов) со стандартного устройства ввода (которым в первом приближении будем считать клавиатуру), а результаты своей работы представляет на стандартном устройстве вывода (коим договоримся считать экран монитора). А совсем-совсем недавно - из главы 8, - мы узнали, что в POSIX-системах любое устройство - не более чем имя специального файла, именуемого файлом устройства. И, таким образом, ничто не запрещает нам подменить специальный файл устройства ввода или устройства вывода любым иным файлом (например, обычным текстовым). Откуда и будут в этом случае браться входные данные или куда будет записываться вывод команды. Перенаправление вывода команды обозначается следующим образом: $ command > filename или $ command >> filename В первом случае (одиночный символ Во втором же случае (двойной символ Перенаправление ввода выглядит так: $ command < filename Конечно, теоретически можно представить себе и присоединяющее перенаправление ввода, однако практически оно вряд ли может найти применение. Простейший случай перенаправления - вывод результата исполнения команды не на экран, а в обычный текстовый файл. Например, конструкция $ ls dir1 > list создаст файл, содержанием которого будет список файлов каталога $ ls dir2 >> list к этому списку добавится и содержимое каталога При перенаправлении ввода команда получает данные для своей работы из входящего в командную конструкцию файла. Например, конструкция $ sort < list выведет на экран строки файла list, отсортированных в порядке возрастания значения ASCII-кода первого символа, а конструкция $ sort -r < list осуществит сортировку строк того же файла в порядке, обратном алфавитному (вернее, обратном порядку кодов символов, но это нас в данном случае не волнует). В одной конструкции могут сочетаться перенаправления ввода и вывода, как в режиме замещения, так и в режиме присоединения. Так, конструкция $ sort -r < list > list_r не только выполнит сортировку строк файла $ sort -r < list >> list добавит по-новому отсортированный список в конец существующего файла Возможности построения командных конструкций не ограничиваются перенаправлением ввода/вывода: результаты работы одной команды могут быть переданы для обработки другой команде. Это достигается благодаря механизму программных каналов (pipe) или конвейеров - последний термин лучше отражает существо дела. При конвейеризации команд стандартный вывод первой команды передается не в файл, а на стандартный ввод следующей команды. Простой пример такой операции - просмотр списка файлов: $ ls -l | less Перенаправление вывода команды Конвейеризация команд может быть сколь угодно длинной. Возможно также объединение конвейеризации команд и перенаправления в одной конструкции. Кроме того, команды в конструкции могут быть сгруппированы с тем, чтобы они выполнялись как единое целое. Для этого группа команд разделяется символами ; и пробелами, как при последовательном выполнении команд, и заключается в фигурные скобки. Так, если нам требуется перенаправить вывод нескольких команд в один и тот же файл, вместо неуклюжей последовательности типа $ command1 > file ; command2 >> file ; ... ; commandN >> file можно прибегнут к более изящной конструкции:
$ { command1 ; command2 ; ... ; commandN } > file
Как и многие из ранее приведенных примеров, этот может показаться надуманным. Однако представьте, что вам нужно создать полный список файлов вашего домашнего каталога, разбитый по подкаталогам, да еще и с комментариями, в каком подкаталоге что находится. Конечно, можно вывести состав каждого подкаталога командой
$ { echo "List of my files" ; > echo "My text" ; \
ls text/* ; > echo "My images" ; \
ls images/* ; > echo "My audio" ; \
ls audio/* ; > echo "My video" ; \
ls video/* } > my-filelist
И в результате получить файл такого (условно) содержания, которое мы для разнообразия просмотрим с помощью только что упомянутой команды $ cat my-filelist List of my files My text text/text1.txt text/text2.txt My images images/img1.tif images/img2.tif My audio audio/sing1.mp3 audio/sing2.mp3 My video video/film1.avi video/film2.avi С понятием командных конструкций тесно связано понятие программ-фильтров. Это - команды, способные принимать на свой ввод данные с вывода других команд, производить над ними некоторые действия и перенаправлять свой вывод (то есть результат модификации полученных данных) в файлы или далее по конвейеру - другой команде. Программы-фильтры - очень эффективное средство обработки текстов, и в свое время мы к ним вернемся для подробного изучения. Сценарии оболочки: первые представленияНаш затянувшийся разговор о командах и командном интерфейсе подходит к концу. Честно говоря, начиная этот раздел, я не думал, что он окажется таким длинным. Но это - тот самый случай, когда из песни слова не выкинешь. Напротив, очень многое осталось недосказанным или необъясненным. Что ж - тем больше поводов будет у нас возвращаться к теме команд вновь и вновь. А в заключение этого раздела - еще немного терпения. Потому что было бы несправедливо не уделить чуть-чуть места тому, что придает командному интерфейсу POSIX-систем его несравненную гибкость и универсальность. Заодно способствуя закоснению пользователя в смертном грехе лености. Итак - слово о сценариях оболочки. В самом начале я обмолвился, что шелл - это не просто среда для ввода единичных команд и командных конструкций, но и еще интерпретатор собственного языка программирования. Так вот, сценарии оболочки, именуемые также скриптами, - это и есть программы, написанные на этом языке. Только не заподозрите меня в гнусном намерении учить вас программерству. Господь борони, и в мыслях не держал (тем паче, что и сам-то этим ремеслом не владею в должной для обучения других степени). Нет, просто на протяжении последующих глав нам то и дело придется рассматривать кое-какие примеры готовых сценариев, а подчас и пытаться создавать их собственноручно. Ибо занятие это в элементарном исполнении навыков программирования не требует вообще. В самом простом случае сценарий - это просто одна или несколько команд или (и) командных конструкций с необходимыми опциями и аргументами, сохраненные в виде обычного именованного текстового файла. Сценарии в Unix-системах несколько напоминают batch-файлы, памятные многим по временам MS DOS, или макросы, знакомые пользователям любых развитых прикладных пакетов. Подобно тем и другим, они предназначены в первую очередь для автоматизации часто исполняемых рутинных операций. В частности, именно они позволяют избежать ввода длинных последовательностей в командной строке. Однако значение сценариев не исчерпывается удовлетворением естественной человеческой лени. Они позволяют решать очень широкий круг задач - от конфигурирования системы (в частности, файлы, отвечающие за инициацию любой POSIX-системы, - суть сценарии оболочки, почему и называются сценариями инициализации или стартовыми скриптами) до создания весьма сложных приложений (к классу шелл-скриптов относятся многие менеджеры пакетов) и даже интерактивных web-страниц (даже CGI-скрипты никто не запрещает писать на языке командной оболочки). Именно практически неограниченным возможностям создания пользовательских сценариев интерфейс командной строки обязан своей эффективностью. Создание пользовательского сценария - просто, как правда. Для этого всего и нужно:
С принципами создания команд и командных конструкций мы в первом приближении разобрались (или пытались разобраться) раньше. А вот способов помещения их в файл существует множество. Можно просто ввести (или вызвать из буфера истории) нужную команду и оформить ее как аргумент команды $ echo "cp -rf workdir backupdir" > mybackup Таким образом мы получили простейший скрипт для копирования файлов из рабочего каталога в каталог для резервного хранения данных, что впредь и будем проделывать регулярно (не так ли?). Аналогичную процедуру можно выполнить с помощью команды $ cat > myarchive и нажимаем Enter. После этого команда остается в ожидании ввода данных для помещения их в новообразованный файл. Не обманем ее ожиданий и проделаем это. Причем можно не жаться и выполнить ввод в несколько строк, например: cd $HOME/archivedir tar cf archive.tar \ ../workdir gzip archive.tar Завершив ввод тела скрипта, все той же клавишей Enter открываем новую строку и набираем комбинацию Control+D, выдающую символ окончания файла. В результате получаем сценарий для архивирования в специально предназначенном для этого каталоге Наконец, сценарий можно создать в любом текстовом редакторе. но это не так интересно (по крайней мере, пока). Да и стоит ли вызывать редактор ради двух-трех строк? Комментариями в шелл-сценариях считаются любые строки, начинающиеся с символа решетки ( Хотя одна строка, начинающаяся символом решетки, в сценарии практически обязательна. И должна она быть первой и выглядеть следующим образом: #!/path/shell_name В данном случае восклицательный знак подчеркивает, что предваряющий его символ решетки ( #!/bin/sh для POSIX-шелла, или #!/bin/bash для оболочки Так что по хорошему в обоих приведенных выше примерах ввод команд сценария следовало бы предварить строкой sha-bang. Конечно, отсутствие имени командной оболочки в явном виде обычно не помешает исполнению шелл-сценария - для этого будет вызван командный интерпретатор по умолчанию, то есть Однако если сценарий предназначен для другой командной оболочки, то без sha-bang он может исполняться неправильно (а если оболочка еще и не из семейства совместимых с POSIX shell - то не исполняться вообще). К слову сказать, если вписать строку sha-bang лениво - то следует еще и воздержаться от комментария в первой строке: в некоторых случаях он может быть интерпретирован как вызов конкретной оболочки (в частности, Теперь остается только выполнить наш сценарий. Сделать это можно разными способами. Самый напрашивающийся - непосредственно вызвать требуемый шелл как обычную команду, снабдив его аргументом - именем сценария (предположим, что он находится в текущем каталоге): $ bash scriptname Далее, для вызова скриптов существует специальная встроенная команда оболочки, обозначаемая символом точки. Используется она аналогично: $ . ./scriptname с тем только исключением, что тут требуется указание текущего каталога в явном виде (что и символизируется Однако наиболее употребимый способ запуска сценариев - это присвоение его файлу так называемого атрибута исполнения. Что это такое, с чем этот атрибут едят и как присваивают - об этом мы уже говорили в главе8. И тут только вспомним, что присвоение атрибута (или, как еще говорят, бита) исполнения - та самая процедура, которая волшебным образом превращает невзрачный текстовый файлишко во всамделишную (хотя и очень простую) программу. Так вот, после присвоения нашему сценарию бита исполнения запустить его можно точно также, как любую другую команду - просто из командной строки: $ ./scriptname Опять же - в предположении, что сценарий находится в текущем каталоге ( Понятие о функцияхИ уж совсем в заключение этой главы осталось сказать только пару слов о функциях командной оболочки. Это - такая же последовательность команд (или даже просто одиночная команда), как и сценарий, но - не (обязательно) вынесенная в отдельный исполняемый файл, а помещенная в тело другого скрипта. В коем она опознается по имени, и может быть выполнена неоднократно в ходе работы этого скрипта. Главное отличие функции от сценария - в том, что она выполняется в том же процессе (и, соответственно, экземпляре шелла), что и заключающий сценарий. Тогда как для каждого скрипта, вызываемого из другого сценария, создается отдельный процесс, порождающий собственный экземпляр шелла. Это может быть важным, если в сценарии определяются некоторые переменные, которые имеют силу только в нем самом. Функции не обязательно помещаются внутрь сценария - их можно собрать в некоторые отдельные файлы, которые именуются библиотеками функций и могут быть использованы по мере надобности. Ранее на протяжении всего повествования неоднократно упоминались (и будут упоминаться впредь) системные библиотеки, в частности, главная библиотека Самая главная команда
Наверное, самую лучшую
На этой земной стороне Хожу я и песенку слушаю, Она шевельнулась во мне... Булат Окуджава Возможно, этот параграф следовало бы назвать главой, и поместить в самое начало книги. Ибо содержание ее - не информация о тех или иных командных, или свойствах системы, а метаинформация - информация о том, как получить нужную информацию. То есть выработке некоторых навыков, которые у истинного POSIX'ивиста должны быть доведены до уровня рефлексов. Однако - лучше поздно, чем никогда, так что - благословясь, приступим. Как как можно логадаться по прочтении предшествующих параграфов этой главы, команд в Unix'ах - немерянное количество. В свежеустановленной Linux-системе минималистского типа (вроде CRUX или Archlinux) их может быть штук 500-700, в минимальной установке BSD - около 800. И это все без учета Иксов и всяческих приложений. К слову сказать - а как определить количество команд? Есть несколько способов, зависящих от используемой ОС, дистрибутива, командной оболочки. Например, во всех BSD-системах все команды из базового комплекта собраны в каталогах $ ls /bin /sbin /usr/bin /usr/sbin | wc Как я уже говорил, во FreeBSD 5-й такой подсчет даст результат - 800-850 команд, в зависимости от версии и полноты установки. В Linux'е размещение исполняемых файлов базовой системы зависит от дистрибутива, однако в первом приближении такой способ подойдет и здесь. Если же учесть, что каждая команда имеет опции, да подчас также в немалом числе, возникает естественный вопрос: как нормальный человек все это может запомнить? Да никак - последует ответ. Потому что запоминать все это изобилие команд нет не только возможности - но и ни малейшей необходимости. Во-первых, команд, которые нужны постоянно, ежедневно и по много раз на дню - не так уж и много. И практически все эти команды имеют прозрачную (правда, английскую) этимологию, или представляют собой простую аббревиатуру от слов, обозначающих соответствующее действие: Во-вторых, и главных, вовсе не нужно помнить все команды, и тем более все их опции: гораздо важнее понимать, каким образом соответствующую информацию можно получить в нужный момент. И вот тут возможны варианты. Для начала - каким образом можно узнать. какие команды имеют место быть в нашей системе? В первом приближении этому послужит клавиша табуляции: нажав ее в пустой командной строке, мы (в большинстве случаев) получим сообщение вроде такого: do you wish to see all XXX possibilities (YYY lines)? И если согласимся с этим предложением (нажав клавишу y), то нашему взору предстанет все доступное изобилие команд. Конечно, с некоторыми оговорками. Клавиша табуляции не извлекает волшебным образом имена команд откуда-то из загашников системы. Нет, она просто выводит список всех исполняемых файлов (то есть файлов, для которых установлен атрибут исполнения - см. главу 8), расположенных в каталогах, перечисленных как значения переменной Из чего следует, что, во-первых, список этот будет разным для обычного пользователя и для администратора. Потому что значения переменной $ echo $PATH обычно можно увидеть список вроде /bin /usr/bin /usr/X11R6/bin /usr/local/bin тогда как для root'а к нему добавятся пути вроде /sbin /usr/sbin /usr/local/sbin Во-вторых, как-то уже упоминалось, что одна и та же команда может иметь более чем одно имя - например, В третьих, получаемый по нажатию табулятора список включает только файлы из каталогов, стандартно перечисляемых в переменной Однако первое представление о наличных командах, тем не менее, с помощью табулятора получить можно. На худой конец всегда есть возможность просто просмотреть содержимое каталогов и исполняемыми файлами, как было сказано выше:
$ ls /{bin,sbin} /usr/{bin,sbin} /usr/local/{bin,sbin}
Остается установить только, что каждая из наличествующих команд делает - не всегда же можно определить ее функции по англо-русскому словарю. И тут нам на помощь приходит самая главная команда - команда Команда Для файлов $ echo $MANPATH что даст примерно такую картину: /usr/man:/usr/share/man:/usr/local/man:/usr/X11R6/man
В BSD к ним добавляется еще и 9-я группа, Нас, как пользователей, в данный момент интересуют в первую очередь команды из 1-й и, поскольку на персоналке каждый юзер - сам себе админ, из 8-й групп, хотя и об остальных категориях забывать не след, иногда позарез нужные сведения отыскиваются в самой неожиданной из них. Внутри групповых подкаталогов можно увидеть многочисленные файлы вида filename.#.gz. Последний суффикс свидетельствует о том, что Для вызова интересующей документации требуется дать команду $ man 1 ls Причем номер группы необходим только в том случае, если одноименные документы имеются в разных группах. Для пользовательских команд он обычно не нужен, так как все равно просмотр групповых каталогов идет сначала в Например, в группе $ man tty Если же ему требуется получить сведения о драйвере устройства $ man 4 tty Однако, повторяю, в данный момент нас интересуют только команды. Так что для получения информации, например, по команде $ man ls после чего можно будет лицезреть примерно такую картину: LS(1) FSF LS(1) NAME ls - list directory contents SYNOPSIS ls [OPTION]... [FILE]... DESCRIPTION List information about the FILEs (the current directory by default). Sort entries alphabetically if none of -cftuSUX nor --sort. То есть в начале Следующая, основная, часть Большинство export PAGER=more в POSIX-совместимых шеллах, или setenv PAGER more в C-shell и его производных. Однако не будем оригинальничать, сохранив Управляющие последовательности команды Аналогично и для большинства других действий (смещение на половину экранной страницы, например: Control+D и Наличие двух типов управляющих последовательностей может показаться излишним усложнением, однако имеет глубокое внутреннее обоснование. Правда, для объяснения его придется существенно забежать вперед. Я надеюсь, что со временем мы доберемся до такой штуки, как текстовые редакторы. Тема эта большая и животрепещущая, служащая предметом священных войн, в которые мы, впрочем, вступать не будем. В рамках нынешнего разговора отметим только, что, за исключением некоторых отщепенцев (в числе коих и автор этих строк), подавляющее большинство записных юниксоидов пользуются одним из двух редакторов - Оба эти редактора относятся к категории командных. То есть все действия по редактированию осуществляются в них обычно не выбором пунктов из меню, а прямыми командными директивами, примерно как в командной строке оболочки. Так вот, одно из кардинальных различий между линиями Поскольку эффективное использование любого редактора командного стиля подразумевает доведенное до автоматизма использование управляющих последовательностей, переключение с Раз уж зашла речь о стилях управляющих последовательностей... В большинстве командных оболочек такое переключение между стилями управления также возможно. Только не параллельное, а альтернативное. И устанавливается оно в конфигурационных файлах пользовательского шелла. Возвратимся, однако, к нашей Однако это - не лучший способ навигации. Потому что управляющие последовательности (не зависимо, в стиле ли Есть и возможность поиска внутри Заканчивая разговор об управляющих последовательностях, еще раз подчеркну: все они относятся не к самой команде Обращение к $ man -k print выведет на экран список всех Исчерпывающим руководством по использованию системы Manual Pages является ее собственная $ man man которая выводит на экран
MAN(1) FreeBSD General Commands Manual MAN(1)
NAME
man -- format and display the on-line \
manual pages
SYNOPSIS
man [-adfhkotw] [-m machine] \
[-p string] [-M path] [-P pager] \
[-S list] [section] name ...
DESCRIPTION
Man formats and displays the on-line manual pages.
...
Система Второй недостаток - в том, что подавляющее большинство Что, впрочем, не так уж и страшно - даже для тех, кто не очень свободно читает Шекспира в подлиннике. В свое время я обнаружил, что переведенные Третий же, и, пожалуй, главный недостаток - сложность навигации внутри объемных К сожалению, о системе Документация в формате Подводя итог, сформулируем, наконец, одну из главных истин POSIX'ивизма: читайте документацию, ибо сеет она разумное, доброе, вечное. Если же нужные доки не валяются под ногами - ищите, и да обрящете (с вероятностью, близкой к 100%). |
|
CITForum © 1997–2025