Создание собственных команд
Статья включает:
Создание сценариев командного интерпретатора по существу представляет собой помещение последовательности команд, которые можно ввести в командной строке в файл для того, чтобы выполнить эти команды в будущем или многократно запускать их без повторного ввода. Сценарии можно использовать для автоматизации повторяющихся задач и решения сложных задач, которые трудно выполнить без многократных попыток и/или внесения изменений в код. Примеры сценариев:
/etc/config/sysinit
, который запускается при загрузке компьютера с операционной системой (см. Управление запуском ЗОСРВ «Нейтрино»); /usr/bin/ph
, который запускает оконное окружение Photon (см. Графическое оконное окружение Photon microGUI).
В операционной системе ЗОСРВ «Нейтрино» чаще всего используется командный интерпретатор ksh, который является общедоступной реализацией командного интерпретатора Korn Shell. Команда sh обычно представляет собой символьную ссылку на командный интерпретатор ksh. Более подробные сведения об этом интерпретаторе см. в:
Операционная система ЗОСРВ «Нейтрино» также предоставляет или использует несколько других сред исполнения сценариев.
В целом сценарии командного интерпретатора наиболее полезны и мощны при запуске программ и изменении файлов в контексте файловой системы, а утилиты sed и gawk предназначены в первую очередь для работы с содержимым файлов.
Сценарий командного интерпретатора можно запустить следующими способами:
sh myscript
. myscript
В этом примере текущий командный интерпретатор вызывает новый командный интерпретатор для исполнения сценария.chmod 744 myscript./myscript
Первая строка многих, если не большинства сценариев имеет следующую форму:
Например, сценарии Korn shell начинаются с такой строки:#! interpreter [arg]
Эта строка начинается с символа #, который указывает на то, что она является комментарием и должна игнорироваться командным интерпретатором, который обрабатывает сценарий. Первая пара символов, #!, не имеет значения для командного интерпретатора, но код загрузчика в модуле procnto распознает их как команду загрузить следующий за ними исполняемый файл,#! /bin/sh
/bin/sh
, и передать ему: Например, сценарий называется my_script и пользователь вызывает его следующей командой:
./my_script my_arg1 my_arg2 ...
В этом случае procnto загружает:
interpreter [arg] ./my_script my_arg1 my_arg2 ...
|
Некоторые интерпретаторы корректируют список получаемых аргументов:
$0
. Для примера рассмотрим простые сценарии, печатающие полученные ими аргументы.
Пусть имеется следующий сценарий ksh_script:
#! /bin/shecho $0for arg in "$@" ; doecho $argdone
Если вызвать его с помощью команды
./ksh_script one two three
то загрузчик вызовет его как
/bin/sh ./ksh_script one two three
а затем ksh удалит себя из списка аргументов. Вывод будет иметь следующий вид:
./ksh_scriptonetwothree
Рассмотрим версию предыдущего сценария для интерпретатора gawk с именем gawk_script, который будет выглядеть следующим образом:
#!/usr/bin/gawk -fBEGIN {for (i = 0; i < ARGC; i++)print ARGV[i]}
Аргумент -f важен, т.к. он указывает, что бы утилита gawk прочитала сценарий из заданного файла. Без опции -f данный сценарий не будет работать ожидаемым образом.
Если этот сценарий запустить командой
./gawk_script one two three
то загрузчик вызовет его как
/usr/bin/gawk -f ./gawk_script one two three
а затем gawk заменит полное путевое имя на gawk. Вывод будет иметь следующий вид:
gawkonetwothree
Версия рассматриваемого сценария на языке perl будет выглядеть следующим образом:
#! /usr/bin/perlfor ($i = 0; $i <= $#ARGV; $i++) {print "$ARGV[$i]\n";}
Если этот сценарий запустить командой
./perl_script one two three
то загрузчик вызовет его как
/usr/bin/perl ./perl_script one two three
а затем perl удаляет себя и имя сценария из списка аргументов. Вывод будет иметь следующий вид:
onetwothree
Чтобы кратко ознакомиться с интерпретатором Korn Shell, рассмотрим сценарий, который ищет строку, переданную ему в командной строке, в исходных и заголовочных C-файлах, которые расположены в текущем дереве каталогов.
#!/bin/sh## tfind:# сценарий, который ищет строки в различных файлах и выводит# эти строки с помощью утилиты lesscase $# in1)find . -name '*.[ch]' | xargs grep $1 | lessexit 0 # успешное завершениеesacecho " Введите команду tfind строка_для_поиска, "echo " где строка_для_поиска — искомая строка "echo " "echo " Например, команда tfind console state просматривает все файлы"echo " в текущем каталоге и его подкаталогах и отображает все "echo " экземпляры фразы console state. "exit 1 # неудачное завершение
Как было описано выше, первая строка указывает программу, /bin/sh
, для интерпретации сценария.
Несколько следующих строк являются комментариями, которые описывают действия, выполняемые сценарием. Далее следует конструкция:
case $# in1)...esac
Команда case...in является встроенной командой интерпретатора Korn и представляет собой одну из структур ветвления, эквивалентную оператору switch языка C.
Последовательность символов $#
является переменной командного интерпретатора. Чтобы обратиться к переменной в командном интерпретаторе, ее имя следует предварить символом $
, тогда командный интерпретатор отличит имя переменной от символьной строки. $#
– особая переменная командного интерпретатора, которая содержит количество командно-строковых аргументов, переданных сценарию.
Константа 1) является возможным значением переменной ветвления, которое эквивалентно оператору case в языке C. Этот код проверяет, был ли передан командному интерпретатору ровно один параметр.
Строка esac завершает оператор case. В командах case и if для указания конца структуры ветвления используется имя команды, записанное справа налево.
Внутри оператора case имеется конструкция:
find . -name '*.[ch]' | xargs grep $1 | less
Эта строка выполняет несколько действий и включает в себя следующие компоненты:
Эти команды объединены при помощи символа конвейера |
. Конвейер – одна из самых мощных возможностей командного интерпретатора; он принимает выходные данные программы, которая указана слева, и передает их в качестве входных данных программе, которая указана справа. Конвейер позволяет строить сложные действия из более простых компонентов. Более подробные сведения см. в Перенаправление ввода и вывода.
Первый компонент конвейера, find . -name '*.[ch]', использует еще одну мощную и распространенную команду. Большинство файловых систем структурировано в виде рекурсивной иерархии каталогов, а утилита find выполняет рекурсивный поиск в этой иерархии. В этом примере утилита find ищет файлы, которые заканчиваются на .c
или на .h
(т.е. исходные и заголовочные файлы языка C), и распечатывает их имена.
Групповые символы имен файлов заключаются в одиночные кавычки, поскольку командный интерпретатор интерпретирует их особым образом. В отсутствие кавычек командный интерпретатор раскрывает групповые символы в текущий каталог, однако в этом примере необходимо, чтобы интерпретацию групповых символов выполнила утилита find, поэтому групповые символы скрыты от командного интерпретатора с помощью кавычек. Более подробные сведения см. в Применение кавычек со специальными символами.
Следующий компонент конвейера, xargs grep $1
, выполняет два действия:
$1
– еще одна специальная переменная командного интерпретатора, которая содержит первый аргумент, переданный сценарию (т.е. искомую строку); find . -name '*.[ch]' -exec grep $i {} | less
Эта команда загружает и запускает программу grep для каждого найденного файла. Команда, которая была использована в примере:
find . -name '*.[ch]' | xargs grep $1 | less
запускает утилиту grep только тогда, когда программа xargs накапливает достаточно файлов для заполнения командной строки, что в общем случае сокращает число вызовов утилиты grep и делает сценарий эффективнее.
Последний компонент конвейера less является утилитой страничного представления вывода. Команда способна сгенерировать большой объем выходных данных, которые выходят за пределы экрана, а утилита less представляет вывод постранично и позволяет перелистывать данные вперед и назад.
Конструкция case также включает в себя команду:
exit 0 # успешное завершение
которая следует за вызовом утилиты find. Эта команда завершает сценарий и возвращает значение 0
. В программировании для командного интерпретатора 0
означает истину или успех, а любое ненулевое значение указывает на ложь или ошибку (в противоположность языку C).
Последний блок команд просто содержит справочную информацию. Если передать сценарию неправильные аргументы, он выведет описание с правилами своего использования, а затем вернет код ошибки.
echo " Введите команду tfind строка_для_поиска, "echo " где строка_для_поиска – искомая строка "echo " "echo " Например, команда tfind console state просматривает все файлы"echo " в текущем каталоге и его подкаталогах и отображает все "echo " экземпляры фразы console state. "exit 1 # неудачное завершение
Сценарии обычно менее эффективны, чем специальные программы, написанные на языке С или С++, поскольку сценарии:
Далее приведены некоторые рекомендации, которые следует учитывать при написании сценариев.
chmod a+x имя_сценария
Сценарий не обязан быть исполняемым, если планируется вызывать его путем передачи в качестве аргумента командному интерпретатору:
ksh имя_сценария
или запускать его с помощью команды "точка":
. имя_сценария
˜/bin/my_script
Предыдущий раздел: перейти