Пользователь ОС LINUX общается с системой через командный интерпретатор (shell). Через него происходит доступ к командам, файловой системе и другим функциям ядра LINUX. Это обычная программа (т.е. не входит в ядро операционной системы LINUX). Ее можно заменить другой или использовать несколько разных версий. Наиболее известны следующие версии:
sh
Классический интерпретатор версии LINUX V7, иначе называемый по фамилии автора Bourne shell.
ksh
Интерпретатор Korn shell, дополняющий классический shell возможностями работы с заданиями пользователя, историей работы и позволяющий редактировать командную строку при помощи команд, аналогичных vi. Является фактически стандартом для POSIX-совместимых систем, в частности, LINUX System V.
csh
Стандартный интерпретатор BSD LINUX и производных от него систем. Отличается улучшенными диалоговыми возможностями, способом присваивания и экспортирования переменных в среду, управляющими конструкциями и рядом других моментов; тоже поддерживает историю и редактирование командной строки. Главное и, по моему мнению, отрицательное его отличие от других интерпретаторов, – это свои управляющие конструкции, не совпадающие с sh.
Свободно распространяемый в виде исходных текстов интерпретатор, называемый “Bourne another shell“, объединяющий все лучшее из остальных интерпретаторов с удобными возможностями редактирования командной строки и работы с историей команд. В настоящее время – фактический стандарт.
В рамках этого курса мы будем рассматривать, в основном, средства, не выходящие за пределы возможностей командных интерпретаторов sh и ksh (в классической версии 1988 года).
Структура командной строки
Командные строки рассматриваются по одной и имеют определенную структуру.
Итак, простая команда – это последовательность слов через пробел. Нажатие клавиши Enter при вводе команды или перевод строки при обработке сценария являются для командного интерпретатора признаком завершения команды. Она обрабатывается и выполняется.
Значением простой команды является ее статус выхода (см. далее) в случае нормального завершения или (восьмеричное) 200+статус при ненормальном завершении.
Пример простой команды:
$ who
oracle pts000 Aug 20 10:08
root console Aug 20 09:03
intdbi pts004 Aug 20 12:45
$
Из простых команд строятся более сложные конструкции: конвейеры и списки.
Конвейер – это последовательность одной или более команд, разделенных |. Стандартный выходной поток каждой команды, кроме последней, соединяется при помощи программного канала со стандартным входным потоком следующей команды. Каждая команда выполняется как отдельный процесс; интерпретатор ожидает окончания последней команды. Статусом выхода конвейера является статус выхода его последней команды. Вот пример простого конвейера:
$ ls | tee save | wc
15 15 100
$
Список – это последовательность одного или более конвейеров, разделенных ;, &, && или || и, возможно, заканчивающаяся ; или &. Из этих четырех символов, ; и & имеют равный приоритет, который ниже, чем у && и || (эти символы тоже имеют равный приоритет). Точка с запятой (;) вызывает последовательное выполнение предшествующего конвейера (т.е. командный интерпретатор ожидает окончания конвейера перед выполнением любых команд, следующих за точкой с запятой). Амперсанд (&) вызывает асинхронное выполнение предшествующего конвейера (т.е. командный интерпретатор не ожидает окончания работы конвейера). Символ && (||) ведет к тому, что следующий за ним список выполняется только в том случае, когда предыдущий конвейер вернул нулевой (ненулевой) статус выхода. В список может входить произвольное количество переводов строк и точек с запятой, разделяющих команды.
Метасимволы командного интерпретатора
Ряд символов, как было описано выше, имеют для командного интерпретатора специальное значение – это метасимволы. Они описаны в табл. 23.
Метасимволы не входят в команды и обрабатываются в несколько проходов до начала выполнения реальных программ.
Таблица 23. Метасимволы командного интерпретатора
| Метасимвол | Интерпретация |
| > | prog>file – переключить стандартный выходной поток в файл |
| >> | prog>>file – добавить стандартный выходной поток к файлу |
| < | prog<file – извлечь стандартный входной поток из файла |
| | | p1 | p2 – передать стандартный выходной поток p1 как стандартный входной поток p2 |
| <<str | “Документ здесь“: стандартный входной поток задается в последующих строках до строки, состоящей только из символов str. По умолчанию в данных интерпретируются метасимволы \, $ и “. Если необходимо предотвратить в данных интерпретацию всех метасимволов, необходимо экранировать строку str, предварив обратной косой или взяв в двойные или одиночные кавычки. |
| * | Задает в имени файла любую строку из нуля или более символов |
| ? | Задает любой символ в имени файла |
| [abc] | Задает любой символ из [abc] в имени файла, при этом допускаются диапазоны, задаваемые при помощи дефиса -. Если первым символом после [ является !, с этой конструкцией сопоставляется любой символ, не входящий в квадратные скобки. |
| ; | Разделитель команд: p1; p2 – выполнить p1, затем p2. |
| &
Выполняет предшествующую команду в фоновом режиме |
|
| `…` | Инициирует выполнение команд(ы) в …; `…` заменяется на полученный в результате выполнения стандартный выходной поток |
| (…) | Инициирует выполнение команд(ы) … в порожденном командном интерпретаторе |
| $1,$2,…$9 | Заменяются аргументами командного файла |
| $var | Значение переменной (ключевого параметра) var в сеансе |
| ${var} | Значение var: исключает коллизии в случае конкатенации переменной с последующим текстом |
| \ | \c – использовать непосредственно символ c, \перевод строки – отбрасывается |
| ‘…’ | Непосредственное использование того, что в кавычках |
| “…” | Непосредственное использование, но после того, как будут интерпретированы метасимволы $, `…` и \ |
| # | Начало комментария |
| Var=value | Присваивает значение value переменной var |
| P1&&p2
Выполнить p1; в случае успеха выполнить p2 |
|
| P1||p2 | Выполнить p1; в случае неудачи выполнить p2 |
Примечание
Большинство метасимволов будет рассматривается по ходу изложения. Здесь мы остановимся на тех из них, которые используются для генерации имен файлов и экранирования.
Перед выполнением команды каждое слово-аргумент команды просматривается в поисках метасимволов *, ? и [. Если в слове есть один из этих символов, слово рассматривается как шаблон . Такое слово заменяется отсортированными в алфавитном порядке именами файлов, соответствующих шаблону. Если ни одно их имен файлов не соответствует шаблону, слово оставляется без изменений.
При таком количестве метасимволов интерпретатора необходимо иметь возможность экранировать специальный символ от интерпретации. Для этого можно использовать апострофы, кавычки или обратную косую. При этом кавычки одного вида могут экранировать кавычки другого вида. Обратите внимание, что кавычки “”, в отличие от апострофов, не экранируют строку полностью – интерпретатор заглядывает внутрь кавычек в поисках $, `…` и \.
В кавычках могут содержаться переводы строк, пробелы, табуляции, символы ;, &, (, ), |, ^, < и >. Задавая имя файла в кавычках, можно создать файлы с такими нетривиальными символами в именах. Впрочем, делать это не рекомендуется, так как работать с ними будет явно неудобно.
Создание сценариев
Имея последовательность команд, которую придется многократно использовать, преобразуем ее для удобства в “новую” команду со своим именем и будем использовать ее как обычную команду. Предположим, что вам как администратору предстоит часто подсчитывать количество пользователей, работающих в настоящий момент в системе, при помощи простого конвейера
$ who | wc -l
и для этой цели нужна новая программа nu.
Первым шагом будет создание обычного текстового файла, содержащего текст конвейера. Можно воспользоваться вашим любимым текстовым редактором, а можно проявить изобретательность:
$ echo 'who | wc -l' >nu
Интерпретатор является такой же программой, как редактор, who или wc. Раз это программа, ее можно вызвать и переключить ее входной поток. Итак, запускаем интерпретатор с входным потоком, поступающим из файла nu, а не с терминала:
$ who
oracle pts000 Aug 20 10:08
root console Aug 20 09:03
intdbi pts004 Aug 20 12:45
$ cat nu
who | wc -l
$ sh < nu
3
$
Результат получился таким же, как и при вводе команды с терминала. Как и многие другие программы, интерпретатор обрабатывает файл, если он указан в качестве аргумента; вы с тем же успехом могли бы задать:
$ sh nu
На самом деле, этот вызов отличается, так как входной поток sh остается связанным с терминалом.
Не хотелось бы вводить sh каждый раз, кроме того, это создает различие между командами, написанными на языке shell, и другими выполняемыми файлами. Поэтому, если текстовый файл предназначен для выполнения, то интерпретатор считает, что он состоит из команд (интерпретатор csh требует, чтобы файл начинался с #).
Все, что вам нужно сделать, это объявить файл nu выполняемым, задав:
$ chmod +x nu
а затем вы можете вызывать его посредством
$ nu
На самом деле, при выполнении команды nu создается новый процесс интерпретатора (порожденный интерпретатор), который и выполняет команды, содержащиеся в nu. Чтобы команда выполнялась в том же интерпретаторе, необходимо поставить перед вызовом команды точку (.). Заметьте, что
$ . nu
выполняется быстрее, чем простой вызов nu.
В большинстве программ надо использовать аргументы – файлы, флаги и т.д. В соответствии с синтаксисом командной строки, это можно сделать, передавая их после имени команды через пробелы.
Предположим, необходимо программу cx для установки права доступа к файлу на выполнение, так что
$ cx nu
есть сокращенная запись для
$ chmod +x nu
Создать такой сценарий не сложно. Остается только один вопрос – как получить в программе доступ к имени файла-аргумента. Для этого в командном интерпретаторе используются позиционные параметры.
При выполнении командного файла, каждое вхождение $1 заменяется первым аргументом, $2 – вторым и так далее до $9. $0 заменяется именем выполняемой команды. Поэтому, если файл cx содержит строку
chmod +x $1
то при выполнении команды
$ cx nu
порожденный интерпретатор заменит $1 первым аргументом команды nu.
Значения позиционным параметрам присваиваются при вызове сценария, при вызове функции в сценарии или явно, с помощью команды set.
Как быть, если нужно работать с несколькими аргументами, например, заставить программу cx делать выполняемыми несколько файлов? Можно включить девять аргументов в командный файл (явно можно задавать только девять аргументов, так как конструкция $10 распознается как “первый аргумент, за которым следует 0″):
chmod +x $1 $2 $3 $4 $5 $6 $7 $8 $9
Если пользователь такого командного файла задаст менее девяти аргументов, то оставшиеся окажутся пустыми строками и только настоящие аргументы будут переданы chmod порожденным интерпретатором. Но такое решение не подходит, если количество аргументов превышает девять.
Интерпретатор предоставляет специальный параметр $*, который заменяется всеми аргументами команды, независимо от их количества. С учетом этого, правильное определение cx будет таким:
chmod +x $*
Все позиционные и специальные параметры, поддерживаемые командным интерпретатором, представлены в табл. 24.
Таблица 24. Позиционные и специальные параметры командного интерпретатора
| Параметр | Назначение |
| $0 | Имя выполняемой команды |
| $1,$2,…$9 | Заменяются аргументами командного файла |
| $# | Количество аргументов |
| $* | Все аргументы, передаваемые интерпретатору. “$*” является единым словом, образованным из всех аргументов, объединенных вместе с пробелами. |
| $@ | Аналогично $*. “$@” идентично аргументам: пробелы в аргументах игнорируются, и получается список слов, идентичных исходным аргументам. |
| $- | Флаги, установленные в интерпретаторе. |
| $? | Значение, возвращенное последней выполненной командой (статус выхода). |
| $$ | Номер процесса интерпретатора. |
| $! | Номер процесса последней команды, запущенной асинхронно с помощью &. |
Переменные и присваивание
Подобно большинству языков программирования, командный интерпретатор имеет переменные, которые называют еще ключевыми параметрами (поскольку они предаются по имени – ключу).
Переменные можно создавать, изменять и выбирать их значения. Для присваивания значения переменной применяется конструкция:
переменная=значение
Обратите внимание на отсутствие пробелов до и после знака присваивания. Вспомните, что командный интерпретатор считает пробелы разделителями слов. Если поставить пробел после знака присваивания, то интерпретатор не изменит значения переменной, но будет искать команду с именем значение.
Присваиваемое значение должно выражаться одним словом, и его следует взять в кавычки, если оно содержит метасимволы, которые не нужно обрабатывать.
Создание (определение) переменной происходит при первом присваивании ей значения. Переменные не нужно явно объявлять до момента их использования. Если переменная не объявлена (не получила значения), при обращении к ней будет получена пустая строка. Все переменные в командном интерпретаторе – строковые, поэтому тип переменной задавать не надо. Некоторые команды интерпретируют строки как числа.
Многие переменные, как, например, PATH, имеют специальное значение для интерпретатора. По традиции, такие переменные называют встроенными и обозначают прописными буквами, а обычные переменные – строчными. Основные встроенные переменные представлены в табл. 25.
Таблица 25. Встроенные переменные командного интерпретатора
| Переменная | Значение |
| $HOME | Начальный каталог пользователя. |
| $PATH | Путь для поиска выполняемых команд. |
| $CDPATH | Путь поиска для команды cd. |
| $IFS | Список символов, разделяющих слова в аргументах |
| Файл почтового ящика. Командный интерпретатор информирует пользователя о получении почты в указанный файл. | |
| $MAILCHECK | Эта переменная определяет, как часто (в секундах) интерпретатор будет проверять поступление почты в файл, определяемый переменной MAIL. По умолчанию принято значение 600 секунд. При установке в 0, интерпретатор будет проверять почту перед каждой выдачей строки-приглашения. |
| $PS1 | Строка-приглашение, по умолчанию принята ‘$ ‘ |
| $PS2 | Строка-приглашение при продолжении командной строки, по умолчанию принята ‘> ‘ |
Типичным примером использования переменных является хранение в них длинных строк, таких как имена файлов:
$ pwd
/home/intdbi/dosapps/doc/book/LINUX/shell
$ dir=`pwd`
$ cd
$ ln $dir/cx .
...
$ cd $dir
$ pwd
/home/intdbi/dosapps/doc/book/LINUX/shell
Встроенная команда интерпретатора set, при вызове без параметров показывает значение всех определенных переменных.
Продожить читать статью “Командный интерпретатор”
Похожие записи
No user прокомментировали сообщение
Оставить комментарий