В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Язык shell
Основные понятия языка shell
В дальнейшем изложении слово shell будет употребляться в двух смыслах - как имя языка программирования и как название командного интерпретатора.
Для нас shell важен прежде всего как мощный язык мобильного программирования. Предваряя дальнейшее изложение, отметим имеющиеся в нем возможности комбинирования команд с помощью конвейеров, подстановки значений переменных и результатов выполнения команд, генерации имен файлов по шаблонам.
Свойства shell как интерактивного командного интерпретатора, непосредственно взаимодействующего с пользователем, хранение и использование истории сеанса, возможности редактирования командной строки и т.п., на ваш взгляд, менее актуальны, поскольку современный пользовательский интерфейс строится на иной основе.
Выделим основные понятия языка shell на лексическом уровне.
Под пробелом в дальнейшем понимается не только собственно пробел, но также и символ табуляции.
Слово - это лексема, отличная от знака операции.
Имя - последовательность букв, цифр, символов подчеркивания, начинающаяся с буквы или подчеркивания.
Параметр - имя, цифра или любой из символов *, @, #, ?, -, $, !.
Комментарий - лексема, начинающаяся с символа #, а также вся последующая часть строки.
На синтаксическом уровне различаются несколько видов команд.
Простая команда - последовательность полей с разделителями (обычно пробелами) между ними. Первое поле определяет имя команды, которая будет выполняться; оставшиеся поля, за исключением присваиваемых параметрам и перенаправления ввода/вывода (см. далее), передаются команде в качестве аргументов. Имя команды передается как аргумент 0.
Значение простой команды - ее код завершения.
Команда - это либо простая команда, либо одна из управляющих конструкций (см. далее). Кодом завершения команды является код завершения последней выполненной простой команды.
Конвейер - последовательность команд, разделенных знаком | . Стандартный вывод всех команд, кроме последней, направляется на стандартный ввод следующей команды конвейера. Каждая команда выполняется как самостоятельный процесс; shell ожидает завершения последней команды, код завершения которой становится кодом завершения конвейера. Формально будем считать простую команду частным случаем конвейера.
Список - последовательность из одного или нескольких разделенных символами ;, &, && или || конвейеров, она может заканчиваться символами ; или & . Из четырех указанных операций ; и & имеют равные приоритеты, меньшие, чем у && и ||. Приоритеты последних также равны между собой. Символ ; означает, что конвейеры будут выполняться последовательно, а & - параллельно (т. е. shell не ожидает завершения конвейера ). Операция && ( || ) означает, что список, следующий за ней, будет выполняться лишь в том случае, если код завершения предыдущего конвейера нулевой (ненулевой). В списке в качестве разделителя конвейеров вместо символа ; можно использовать символ перевода строки.
Командная строка - строка текста на языке shell.
Shell-процедура - файл, содержащий программу на языке shell.
Для выполнения (почти) каждой простой команды shell порождает отдельный процесс, в рамках которого выполняется программа, хранящаяся в файле, заданном именем команды. Программа может быть выполнимой, т. е. содержать машинные инструкции, или представлять собой shell-процедуру - содержать текст на языке shell.
Далее при описании синтаксиса конструкций языка shell и способа вызова служебных программ будут использоваться следующие соглашения:
- в квадратные скобки заключаются необязательные части конструкций;
- многоточие означает повторение предыдущей части конструкции произвольное число раз.
Конвейеры и примеры их использования
Конвейер - одна из самых красивых конструкций ОС Unix, вошедшая, разумеется, и в стандарт POSIX. Идея его проста, но на редкость продуктивна. С помощью конвейеров удается комбинировать возможности, предоставляемые разными командами, получая по существу новое качество.
Например, утилита ls не подсчитывает число файлов в каталоге, а лишь выдает информацию о них. С другой стороны, служебная программа wc способна подсчитать число строк в файле, но не имеет отношения к распечатке содержимого каталогов. Если же построить конвейер из двух упомянутых команд, количество файлов в каталоге легко вычисляется. Например, результатом работы конвейера (см. листинг 2.1) на нашей установке ОС Linux будет число 92 (утилита wc, вызванная без аргументов, обрабатывает файл стандартного ввода, который в данном случае является результатом работы команды ls ). Значит, в каталоге /bin 91 файл, если считать и элементы, соответствующие текущему и вышележащему каталогам (первая строка выдачи ls содержит суммарное число блоков, занятых файлами каталога).
ls -al /bin | wc -lЛистинг 2.1. Пример конвейера.
Еще один пример. Пусть необходима информация о файлах текущего каталога, модифицированных в октябре. К цели ведет конвейер, показанный в листинге 2.2:
ls -al | grep "Oct "Листинг 2.2. Еще один пример конвейера.
Служебная программа grep играет здесь роль фильтра, который пропускает для вывода только часть строк, выдаваемых ls.
Можно выстроить и трехступенчатый конвейер, если требуется подсчитать число файлов, модифицированных в октябре (см. листинг 2.3):
ls -al | grep "Oct " | wc -lЛистинг 2.3. Пример трехступенчатого конвейера.
Здесь утилиту grep с еще большим правом можно назвать фильтром.
Приведем еще один пример конвейера, полезного, когда нужна подробная информация о большом каталоге (см. листинг 2.4):
ls -Rl /dev | moreЛистинг 2.4. Конвейер для поэкранного просмотра результатов.
Связующее звено между последовательными компонентами конвейера называется каналом . Иными словами, для интерпретации конвейера shell создает временный файл типа "канал", с одного конца в него заносят данные, а с другого - читают. С помощью служебной программы tee можно организовать ответвление канала, т. е. помещать информацию не только на стандартный вывод, но и в указанные файлы:
tee файл ...
Например, если нужно не только подсчитать число файлов из текущего каталога, модифицированных в октябре, но и поместить информацию о них в файл для последующего анализа, следует построить четырехступенчатый конвейер (см. листинг 2.5):
ls -al | grep "Oct" | tee /tmp/tmpinf | wc -lЛистинг 2.5. Четырехступенчатый конвейер.
В результате его выполнения на экране появится сообщение о количестве нужных файлов, а в файле /tmp/tmpinf - информация о них.