Командная оболочка как средство программирования
Необходимость использования сценариев командной оболочки
Одна из причин применения сценариев командной оболочки — возможность быстрого и простого программирования. Командная оболочка всегда есть даже в самых упрощенных установках ОС Linux. Хотя внешне командная оболочка очень похожа на режим командной строки в ОС Windows, она гораздо мощнее и способна выполнять самостоятельно очень сложные программы. Командная оболочка выполняет программы оболочки, часто называемые сценариями или скриптами, которые интерпретируются во время выполнения. Такой подход облегчает отладку, потому что можно выполнять программу построчно и не тратить время на перекомпиляцию. Но для задач, которым важно время выполнения или необходимо интенсивное использование процессора, командная оболочка оказывается неподходящей средой.
Командная оболочка
Командная оболочка — это программа, которая действует как интерфейс между пользователем и ОС Linux, позволяя вводить команды, которые должна выполнить операционная система. В ОС Linux вполне может сосуществовать несколько установленных командных оболочек, и разные пользователи могут выбрать ту, которая им больше нравится. На рис. 1 показано, как командная оболочка (на самом деле, две командные оболочки: bash и csh) и другие программы располагаются вокруг ядра Linux.
Поскольку ОС Linux — модульная система, можно вставить и применять одну из множества различных стандартных командных оболочек. В Lmux стандартная командная оболочка, всегда устанавливаемая как /bin/sh и входящая в комплект средств проекта GNU, называется bash (GNU Bourne-Again SHell). В данной работе используется оболочка bash версии 3, ее функциональные возможности являются общими для всех командных оболочек, удовлетворяющих требованиям стандарта POSIX.
Рис. 1. Укрупненная архитектура ОС Linux
Каналы и перенаправление
Прежде чем заняться подробностями программ командной оболочки, необходимо сказать несколько слов о возможностях перенаправления ввода и вывода программ (не только программ командной оболочки) в ОС Linux.
Перенаправление вывода
Ранее были рассмотрены некоторые виды перенаправления, например, такие как:
$ ls -l > lsoutput.txt
сохраняющие вывод команды ls в файле с именем lsoutput.txt.
Однако перенаправление позволяет сделать гораздо больше, чем демонстрирует этот простой пример. Cейчас нужно знать только то, что дескриптор файла 0 соответствует стандартному вводу программы, дескриптор файла 1 — стандартному выводу, а дескриптор файла 2 — стандартному потоку ошибок. Каждый из этих файлов можно перенаправлять независимо друг от друга. На самом деле можно перенаправлять и другие дескрипторы файлов, но, как правило, нет нужды перенаправлять любые другие дескрипторы, кроме стандартных: 0, 1 и 2.
В предыдущем примере стандартный вывод перенаправлен в файл с помощью оператора >. По умолчанию, если файл с заданным именем уже есть, он будет перезаписан. Для дозаписи в конец файла используйте оператор >>. Например, команда
$ ps >> lsoutput.txt
добавит вывод команды ps в конец заданного файла. В этом примере и далее знак $ перед командой – приглашение ОС Linux.
Для перенаправления стандартного потока ошибок перед оператором > вставьте номер дескриптора файла, который хотите перенаправить. Поскольку у стандартного потока ошибок дескриптор файла 2, укажите оператор 2>. Часто бывает полезно скрывать стандартный поток ошибок, запрещая вывод его на экран.
Предположим, что вы хотите применить команду kill для завершения процесса из сценария. Всегда существует небольшой риск, что процесс закончится до того, как выполнится команда kill. Если это произойдет, команда kill выведет сообщение об ошибке в стандартный поток ошибок, который по умолчанию появится на экране. Перенаправив стандартный вывод команды и ошибку, вы сможете помешать команде kill выводить какой бы то ни было текст на экран.
Команда $ kill -HUP 1234 > killout.txt 2>killer.txt
поместит вывод и информацию об ошибке в разные файлы.
Если вы предпочитаете собрать оба набора выводимых данных в одном файле, можно применить оператор >2 для соединения двух выводных потоков. Таким образом, команда
$ kill -1 1234 > killerr.txt 2>41
поместит свой вывод и стандартный поток ошибок в один и тот же файл. Обратите внимание на порядок следования операторов. Приведенный пример читается как "перенаправить стандартный вывод в файл killerr.txt, а затем перенаправить стандартный поток ошибок туда же, куда и стандартный вывод". Если вы нарушите порядок, перенаправление выполнится не так, как вы ожидаете.
Поскольку обнаружить результат выполнения команды kill можно с помощью кода завершения, часто не потребуется сохранять какой бы то ни было стандартный вывод или стандартный поток ошибок. Для того чтобы полностью отбросить любой вывод, можно использовать универсальную "мусорную корзину" Linux, /dev/null, следующим образом:
$ kill -1 1234 >/dev/null 2>fil
Перенаправление ввода
Также как вывод можно перенаправить ввод. Например $ more < killout.txt
Каналы
Процессы можно соединять с помощью оператора канала | . Как пример, можно применить команду sort для сортировки вывода команды ps.
Если не применять каналы, придется использовать несколько шагов, подобных следующим:
$ ps > psout.txt
$ sort psout.txt > pasoirt.out
Соединение процессов каналом даст более элегантное решение:
$ ps | sort > pssort.out
При желании увидеть на экране вывод, разделенный на страницы, можно подсоединить третий процесс, more:
$ ps | sort | more
Предположим, что необходимо видеть все имена выполняющихся процессов, за исключением командных оболочек. Можно использовать следующую командную строку:
$ ps -xо comm | sort | uniq | grep -v sh | more
В ней берется вывод команды ps, сортируется в алфавитном порядке, из него извлекаются процессы с помощью команды uniq, применяется утилита grep -v sh для удаления процесса с именем sh и в завершение полученный список постранично выводится на экран. Это более элегантное решение, чем строка из отдельных команд, каждая со своими временными файлами.
Командная оболочка как средство программирования
Есть два способа написания программ оболочки. Вы можете ввести последовательность команд и разрешить командной оболочке выполнить их в интерактивном режиме или сохранить эти команды в файле и затем запускать его как программу.
Интерактивные программы
Легкий и очень полезный во время обучения или тестирования способ проверить работу небольших фрагментов кода— просто набрать с клавиатуры в командной строке сценарий командной оболочки.
Предположим, что у вас большое количество файлов на языке С, и вы хотите проверить наличие в них строки posix. Вместо того чтобы искать в файлах строку с помощью команды grep и затем выводить на экран отдельно каждый файл, можно выполнить всю операцию в интерактивном сценарии:
$ for file in *
> do
> if grep -l POSIX $file
> then
> more $file
> fi
> done posix
This is a file with POSIX in it - treat it well
$
Обратите внимание на то, как меняется знак $, стандартное приглашение командной оболочки, на символ >, когда оболочка ожидает очередной ввод. Вы можете продолжить набор, дав оболочке понять, когда закончите, и сценарий немедленно выполнится.
В этом примере команда grep выводит на экран найденные ею имена файлов, содержащих строку posix, а затем команда more отображает на экране содержимое файла. В конце на экран возвращается приглашение командной оболочки. Обратите внимание также на то, что вы ввели переменную командной оболочки, которая обрабатывает каждый файл для самодокументирования сценария. С таким же успехом можно использовать переменную i, но имя file более информативно с точки зрения пользователей.
Командная оболочка также обрабатывает групповые символы или метасимволы (часто называемые знаками подстановки). Например, символ * - знак подстановки, соответствующий строке символов, односимвольный знак подстановки ? соответствует одиночному символу. Подстановочный шаблон из фигурных скобок {} позволяет формировать множество из произвольных строк, которое командная оболочка раскроет. Например, команда
$ ls my_{finger, toe}s
будет проверять файлы с именами my_figers и my_toes в текущем каталоге.
Каждый раз вводить последовательность команд утомительно. Можно сохранить команды в файле, который принято называть сценарием или скриптом командной оболочки, а затем выполнять эти файлы.
Создание сценария
Создать файл, содержащий команды, можно помощью любого текстового редактора. В данной работе рекомендуется использовать встроенный в mc редактор. Для создания нового файла в mc используйте комбинацию клавиш Shift+F4. Создайте файл с именем first с таким содержимым:
#!/bin/sh
# first
# Этот файл просматривает все файлы в текущем каталоге для поиска строки
# POSIX, а затем выводит имена найденных файлов в стандартный вывод.
for file in *
do
if grep -q POSIX $file
then
echo $file
fi
done
exit 0
Комментарий начинается со знака # и продолжается до конца строки. Принято знак # ставить в первой символьной позиции строки. Первая строка #! /bin/sh — это особая форма комментария; символы #! сообщают системе о том, что следующий за ними аргумент — программа, применяемая для выполнения данного файла. В данном случае программа /bin/sh — командная оболочка, применяемая по умолчанию.
Команда exit гарантирует, что сценарий вернет осмысленный код завершения. Он редко проверяется при интерактивном выполнении программ, но если вы хотите запускать данный сценарий из другого сценария и проверять, успешно ли он завершился, возврат соответствующего кода завершения очень важен. Даже если вы не намерены разрешать вашему сценарию запускаться из другого сценария, все равно следует завершать его с подходящим кодом.
В программировании средствами командной оболочки ноль означает успех. Поскольку представленный вариант сценария не может обнаружить какие-либо ошибки, он всегда возвращает код успешного завершения.
В сценарии не используются никакие расширения и суффиксы имен файлов; ОС Linux и UNIX, как правило, редко применяют при именовании файлов расширения для указания типа файла.