
14. Основы программирования Shell, Sed и Awk.
Выполнение отдельных команд в командном интерпретаторе не всегда является эффективным средством работы с SHELL оболочкой. Довольно часто требуется выполнять одни и те же последовательности действий при работе с операционной системой Linux каждый месяц, каждую неделю, каждый день и иногда и несколько раз в день. Например, предположим, вы работаете на фирме тестером программного обеспечения (Test Manager). Каждый день вам требуется в командной оболочке Linux выполнять один тот набор действий, а именно: монтирование устройства CD-ROM; копирование всей информации с него в папку, скажем, /opt/program на жестком диске; демонтирование CD-ROM; чтение файла readme из этой папки; установка программы с жесткого диска из папки /opt/program; создания нового файла отчета в директории /home/user/report_program удаление всего содержимого дистрибутива с жесткого диска. И это притом, что основная ваша работа заключается в тестировании программного обеспечения на предмет выявления недоработок (bags). Задача на первый взгляд простая, но выполнять подобные действия по несколько раз в день, притом, что вы занимаетесь и другими делами, неудобно. Или, например, вы работаете в фирме системным администратором и обслуживаете около 50 компьютеров. Каждый день вам требуется раскопировать на все компьютеры один и тот же файл с инструкциями на текущий день директора фирмы для всех подчиненных. Кроме того, в ваши задачи также входит в конце рабочего дня сохранить все данные каждого пользователя на общем сервере фирмы с персональных компьютеров подчиненных. Задача также на первый взгляд простая, но работа по набору команд в командном интерпретаторе для 50 компьютеров займет много времени. А если к тому же вы при наборе будите ошибаться, например, от усталости? Данные для директора и их владельца очень важны, и потерять их Вам никак нельзя. Но это еще простые действия. А представьте, что названия файлов отчетов, название папок с данными, имена компьютеров каждый раз будут меняться? Что тогда делать? Выход один – написать файл-сценария, т.е. создать текстовый файл, в котором требуется описать всю последовательность команд с путями, опциями, аргументами, выражениями, действиями и так далее для выполнения определенного сценария. Например, резервирования данных. После ввода команд в текстовый файл-сценария, данный файл делают исполняемым или выполняют его специальных операторов выполнения командного интерпретатора. Использование файлов сценария является особенно эффективным, если вам очень часто требуется выполнять последовательность из большого числа команд. Также является эффективным средством, если в зависимости от результатов выполнения предыдущих команд зависит выполнение следующих. С помощью файлов-сценариев можно также использовать арифметические и логические выражения, создавать циклы, обеспечивающие многократное выполнение группы команд Linux.
Создание файлов-сценария. Создания сценариев представляет собой последовательный набор команд, операторов командного интерпретатора и некоторых других символов в текстовом файле. Файлы-сценария также называют скриптами, а командные интерпретаторы латинским названием SHELL. В связи с тем, что на сегодняшний день существуют разные командные интерпретаторы, написание файла-сценария с использованием дополнительных символов, например, метасимволов, совместно с командами не должно противоречить правилам синтаксиса выбранного командного интерпретатора, в котором предполагается выполнять данный скрипт. Процесс написания таких файлов называют SHELL программированием. Рассмотрим процесс программирования на примере интерпретатора BASH. Таким образом, скрипты и правила написания скриптов в данной лабораторной работе могут быть не переносимы на другие интерпретаторы, например, такие как С Shell или TC Shell.
Последовательность #!. Написание любого скрипта начинается с принадлежности его к одному из командных интерпретаторов. В первой строке скрипта обычно пишут последовательность #! , которая указывает системе, какой интерпретатор должен выполнить команды из данного сценария. Если первый символ пробел, считается, что сценарий написан для BASH или PDKSH. Если сценарий начинается только с символа # , то для его выполнения необходим TC Shell. Если же за символом # следует символ !, ядро запустит интерпретатор, путь которого указан далее в этой строке. Например, для BASH будет следующая запись: #!/bin/sh . Пробела или одиночного символа # в начале сценария достаточно для интерпретаторов BASH Shell и TC Shell только при условии, что они будут считывать свой сценарий. Чтобы один интерпретатор распознал сценарии другого, необходимо включать в сценарий символы #! , после чего указывается путь интерпретирующей программы. Тогда при вызове сценария будет прекращена работа текущего интерпретатора, вместо него будет загружен сценарий другого типа, а затем выполнен сценарий. Рекомендуется всегда начинать все сценарии с последовательности #! . Также строки, начинающиеся с символа # можно использовать для комментариев действий пользователя в скрипте. Встретив символ #, интерпретатор shell игнорирует эту строку. Каждый комментарий должен завершаться символом окончания строки. Использование комментариев является признаком хорошего тона.
Расширение и запуск скриптов. Обычно файлы-сценариев имеют не только имена, но также и расширения. Чаще всего в качестве расширений используют комбинацию букв sh от латинского слова shell. По такому расширению, не открывая файл, сразу понятно, что это shell скрипт, так как нам опять же понятно, что файл с расширением .c скорее всего является входным файлом языков высокого уровня С и С++. После набора содержимого файла, файл сохраняется. Запустить файл можно двумя способами либо сделать его исполняемым с помощью команды chmod, либо запускать его с помощью специальных операторов командного интерпретатора: sh и . Обычно пользователи задают для файл-сценария восьмеричные значения 750 или 550. В следующем примере сделаем скрипт script.sh выполняемым с помощью команды chmod и запустим его на выполнение из текущей директории в фоновом режиме.
chmod u+x script.sh
./script.sh&
Теперь вернем файлу предыдущие атрибуты и запустим его на выполнение с помощью оператора BASH.
chmod u-x script.sh
sh script.sh&
Команда echo. Помимо перечня стандартных команд Linux, самое простое, что можно использовать в скрипте – это вывод текстовых комментариев пользователю с помощью команда echo. Например, данную команду можно использоваться для приглашения пользователя выполнить какое-нибудь действие или использовать для приветствия пользователя. В следующем примере с помощью echo отображается приветствие.
echo “Добрый день!”
Команда read. При создании скриптов вы можете также применять переменные и сценарии, написанные для других интерпретаторов и команд. Команда read служит командой запроса пользователя на ввод информации. Она сочетается с подсказкой пользователю, которая приглашает ввести нужную информацию. Приведем пример использования read.
echo “Введите ваше имя: ”
read your_name
echo “Добрый день,” your_name “!”
Данный скрипт усложнен по отношению к предыдущему. Здесь используется переменная your_name , значение которой потом применяется совместно с текстом.
Использование переменных. Как и языках программирования, в shell Вы также можете использовать переменные, присваивать значения переменным можно через оператор присваивания равно «=». Сначала вводится имя переменной, потом без пробела знак «=», затем без пробела значение переменной. Имя переменной может состоять из любого количества буквенных символов, включая символ подчеркивания. Имя может содержать и цифры, однако не должно начинаться с цифры. Все остальные символы (в частности, восклицательный знак, амперсанд и пробел) в имя входить не должны. Такие символы зарезервированы интерпретатором для специальных целей. Как следствие, имя может состоять только из одного слова, поскольку при синтаксическом анализе команд интерпретатор рассматривает пробел как разделитель имен команд и аргументов. Значение переменной может состоять из любой последовательности символов. В следующем примере присвоим переменной «ppp» значение «www123yyy».
ppp=”www123yyy”
Если вы используете в качестве значения переменной строковое значение, используйте двойные кавычки. После присвоения значения вы можете пользоваться именем переменной для ссылки на это значение, например использовать его в качестве аргумента команд сценария. На значение переменной можно ссылаться посредством ее имени, которое предваряется оператором $. Знак доллара — это специальный оператор, который использует имя переменной для ссылки на ее значение, то есть фактически для ее вычисления. Теперь с помощью уже знакомой команды echo и переменной «ppp» можно отображать значение этой переменной.
echo $ppp
www123yyy
Аргументы командной строки. В сценарии, как и в командах Linux, можно использовать аргументы. Аргумент в сценарии обозначается оператором $ с указанием номера позиции в командной строке. Нумерация параметров начинается с единицы, а заканчивается девятью. Первый параметр задается переменной $1, второй — $2 и т. д. Аргумент $0 резервируется для имени shell-сценария, в качестве которого выступает первое слово, находящееся в командной строке. По умолчанию имеется возможность устанавливать 9 переменных с $1 до $9 . Если вводится несколько аргументов, можно отдельно обращаться к каждому из них по его номеру. В следующем примере в командной строке вводятся три аргумента. Предварительно создадим скрипт arguments с аргументами, а потом его выполним.
Обращаем ваше внимание, если вам требуется использовать аргумент(ы) из нескольких слов, вы должны в командной строке взять его (их) в двойные кавычки. Иногда требуется задать в сценарии точное количество аргументов, это можно выполнить с помощью аргумента $# . Параметр $* позволяет указать все аргументы в командной строке.
Переменная export. Иногда для разных файлов-сценария требуется воспользоваться определенной переменной, которая уже была определена. Переменные, которые вы определяете в интерпретаторе shell, являются локальными для него. В некотором смысле такая переменная принадлежит своему интерпретатору. Непосредственно определить переменную для другого интерпретатора нельзя, однако можно экспортировать определение переменной из одного интерпретатора в другой с помощью команды export. Команда export содержит инструкцию для системы, в соответствии с которой для каждого вновь образованного shell будет определяться копия этой переменной. Каждый новый интерпретатор shell будет иметь собственную копию экспортированной переменной. В следующем примере определим переменную «rrr» и экспортируем ее для других интерпретаторов с помощью команды export.
Арифметические операции – команда let. Команда let — это команда интерпретатора BASH shell, обеспечивающая выполнение операций над арифметическими величинами. С помощью этой команды можно сравнивать числовые значения или выполнять над ними арифметические операции, такие как сложение или умножение. Формат команды: let значение1 оператор значение2. Приведем пример.
$ let 2*5
10
В арифметические выражения, использующие оператор let, можно включать и операторы присваивания. В следующем примере результат умножения двух чисел присваивается переменной total.
$ let “total=2*5”
$ echo $total
10
$
Операторы сравнения часто используются для сравнения числовых значений в управляющих конструкциях, таких как циклы и условные переходы. В следующем примере команды сценария file1 четырежды выводят на экран слово "Привет!". В данном случае для управления выходом из цикла используется оператор let "ttt <= 4", а для увеличения переменной цикла again на единицу — оператор let "ttt = ttt + 1". Обратите внимание на то, что при изменении переменной again ее вычислять не требуется.
File1
ttt=1
while let "ttt<= 4"
do
echo $ttt Привет!
let "ttt = ttt + 1"
done
Выполнение скрипта:
$ file1
Привет!
Привет!
Привет!
Кроме того, вы также можете использовать и другие арифметические операторы. В таблице 1 приведены арифметические операторы и операторы сравнения Bash Shell.
Таблица 1 - Операторы BASH shell
Арифметические операторы |
Функции |
* |
Умножение |
/ |
Деление |
+ |
Сложение |
- |
Вычитание |
% |
Деление с остатком |
Операторы сравнения |
Функции |
> |
Больше чем |
< |
Меньше чем |
>= |
Больше либо равно |
<= |
Меньше либо равно |
= |
Равенство в выражениях |
= = |
Равенство в команде let |
!= |
Не равно |
& |
Логическое И |
| |
Логическое ИЛИ |
! |
Логическое НЕ |
Управляющие конструкции. Управляющие конструкции предназначены для управления ходом выполнения команд shell-сценария. Эти конструкции позволяют организовать повторное выполнение определенной последовательности команд или выбирать для выполнения команды, необходимые в конкретной ситуации. Управляющая конструкция состоит из двух основных компонентов: операции проверки и команд. В результате выполнения сравнения (проверки условия) возвращается значение «истина» или «ложь», а затем на основании полученного результата выполняются определенные команды. Существует два вида управляющих конструкций: циклические (циклы) и условные (условия). Циклическая конструкция используется для повторного выполнения команд, тогда как условная — для выполнения последовательности команд., которая удовлетворяет определенным условиям. В интерпретаторе BASH shell можно использовать три циклические конструкции, while, for и for-in, и две условные — if и case.
Управляющие конструкции while и if — это конструкции общего назначения, которые обычно используются при решении таких задач, как итерационные вычисления и проверка различных условий. Управляющие конструкции case и for ориентированы на более узкий круг задач. Конструкция case является многовариантным оператором и представляет собой частный случай условного оператора if. Эта конструкция часто используется при создании меню. Конструкция for представляет собой цикл, однократно обрабатывающий всю информацию для каждого значения, включенного в список, до тех пор, пока не встретится окончание списка.
Кроме сравнения значений или переменных, управляющие конструкции if и while можно применять для проверки того, успешно или неудачно была выполнена системная команда Linux. Напомним, что в Linux каждая выполняемая команда возвращает код завершения. Если выполнение команды было успешным, ее код завершения равен 0. Если по какой-либо причине команда не была выполнена успешно, кодом завершения будет некоторое положительное значение, указывающее тип ошибки. Управляющие конструкции if и while позволяют проверить, чему был равен код завершения: 0 или некоторому другому значению. Если код завершения равен нулю, значит, выполнение команды было успешным и управляющая конструкция if или while будет завершена.
Команда test. Сравнивать значения можно не только с помощью условных управляющих конструкций, но также с помощью команды test. При сравнении двух значений test возвращает 0 в том случае, если сравнение будет успешным. Команда test позволяет сравнивать целые числа, строки и даже выполнять логические операции. Совместно с командой test применяют опции, которые задают тип сравнения. Полный перечень опций приведен в таблице 2.
Таблица 2. Операции, выполняемые командой test интерпретатора BASH shell
Сравнение целых чисел |
Функция |
-gt |
Больше чем |
-it |
Меньше чем |
-ge |
Больше чем либо равно |
-le |
Меньше чем либо равно |
-eq |
Равно |
-ne |
Не равно |
Сравнение строк |
Функция |
-2 |
Проверка на наличие пустой строки |
-n |
Проверка на наличие строкового значения |
= |
Проверка строк на равенство |
! = |
Проверка строк на неравенство |
str |
Проверка на наличие строки, состоящей из нулей |
Логические операции |
Функция |
-a |
Логическое И |
-о |
Логическое ИЛИ |
i |
Логическое НЕ |
Проверка файлов |
Функция |
-f |
Установка факта существования файла и его регулярности |
-s |
Проверяется, не является ли файл пустым |
-r |
Проверка возможности считывания из файла |
-w |
Проверка возможности записи в файл, а также его изменения |
-x |
Проверяется, является ли файл исполнимым |
-d |
Проверяется, является ли имя файла именем каталога |
-h |
Проверяется, является ли имя файла символической ссылкой |
-c |
Проверяется, обозначает ли имя файла байт-ориентированное устройство |
-b |
Проверяется, обозначает ли имя блок-ориентированное устройство |
Команда test имеет следующий синтаксис:
test значение -опция значение
test строка = строка
В следующем примере покажем пример использования команды test. Сравним целочисленных значения, для этого используем опцию равенства –eq. Для проверки результата выполнения операции сравнения используем код завершения последней выполненной командыtest, который храниться в переменной $? интерпретатораshell.
$ tot=4
$ test $tot -eq 7
$ echo $?
1
Также команда test $tot –eq 7 может быть записана и в другом виде:
$ [ $tot –eq 7 ]
Условные конструкции: if, if-else, elif, case. Интерпретатор BASH shell включает несколько условных управляющих конструкций (табл. 3), которые позволяют выбирать для выполнения определенные команды Linux. Многие из этих конструкций напоминают условные управляющие конструкции в языках программирования, но имеются и некоторые отличия.
Таблица 3 – Управляющие конструкции интерпретаторов bash Shell
Условные управляющие конструкции |
Функция |
** if команда then команда fi ** |
Конструкция if вызывает выполнение действия в случае, если результат проверки истинен |
** if команда then команда else команда fi ** |
Конструкция if-else вызывает выполнение действия в случае, если код завершения проверяемой команды paвен значению «истина», в противном случае выполняется действие else |
** if команда then команда elif команда then команда else команда fi ** |
Конструкция elif дает возможность вкладывать конструкции if, что позволяет выбрать один из многих вариантов; если истинно условие, проверяемое первой конструкцией if, выполняются предусмотренные в ней команды и следующей конструкции elif управление не передается |
** case строка in шаблон) команда;; еsас ** |
Конструкция case сравнивает строковое значение с одним из нескольких шаблонов (образцов). При обнаружении совпадения выполняются команды, соответствующие этому шаблону |
** команда && команда ** |
Логическая операция И возвращает значение 0 («истина»), если обе команды возвращают значение 0; если же одна из команд возвращает ненулевое значение, результат операции И равен «ложь» и данная операция возвращает ненулевое значение |
** команда | | команда ** |
Логическая операция ИЛИ, возвращающая значение 0 («истина») в случае, если одна или обе команды возвращают значение 0 («истина»); если обе команды возвращают ненулевое значение, то результат операции ИЛИ — «ложь» и операция возвращает ненулевое значение |
** ! команда ** |
Логическая операция НЕ, инвертирует код завершения команды |
** Циклические управляющие конструкции ** |
Функция while, until, for, for-in, select |
** while команда do команды done ** |
Конструкция while выполняет действие до тех пор, пока команда проверки возвращает значение «истина» |
** until команда do команды done ** |
Конструкция until выполняет действие до тех пор, пока команда проверки возвращает значение «ложь» |
** Циклические управляющие конструкции ** |
Функция while, until, for, for-in, select |
** for переменная in список-значений do команды done ** |
Конструкция for-in предназначена для обработки списка значений. Переменной последовательно присваиваются значения из списка |
** for переменная do команды done ** |
Конструкция for предназначена для последовательной обработки аргументов сценария. Переменной последовательно присваивается значение каждого аргумента |
** select строка in перечень-элементов do команды done ** |
Конструкция select создает меню на основе элементов заданного списка, а затем выполняется указанная команда (обычно это команда case) |
Условная конструкция if-then . Условная конструкция if ставит условие на выполнение команды. Этим условием является код завершения какой-то конкретной команды Linux. Если команда выполнена успешно (то есть код завершения равен 0), то команды внутри конструкции if выполняются. Если код завершения отличен от 0, то команды внутри конструкции if выполняться не будут. Иногда требуется выбрать один из двух вариантов, в зависимости от того как была выполнены команда Linux. Ключевое слово else конструкции if позволяет выбрать один из двух вариантов. Приведем синтаксис команды if-then-else: