Table of Contents
Генератор отчетов - начало проекта
В этой статье, мы приступаем к созданию программы. Цель данного проекта – показать, как можно использовать разные возможности командной оболочки для создания программ и, что особенно важно, для создания хороших программ.
Будет написан генератор отчетов. Он будет выводить разнообразную информацию о системе и ее состоянии в формате HTML.
Обычно создание программ выполняется в несколько этапов, на каждом из которых добавляются новые функции и возможности. По окончании первого этапа программа будет воспроизводить минимальную HTML-страницу без какой-либо информации. Эту информацию мы добавим на следующих этапе.
Этап первый: минимальный документ
Прежде всего, определим, как выглядит формат правильно сформированного HTML-документа. Он имеет следующий вид:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Заголовок страницы</title> </head> <body> Тело страницы </body> </html>
На первом этапе создадим программу, которая будет выводить эту разметку HTML в стандартный вывод. Написать такую программу очень просто. В текстовом редакторе создадим файл <html>~/bin/sys_info_page</html>:
#!/bin/bash # Программа вывода страницы с информацией о системе echo "<html>" echo " <head>" echo " <title>Page Title</title>" echo " </head>" echo " <body>" echo " Page body." echo " </body>" echo "</html>"
После сохранения файла делаем его выполняемым и пробуем запустить: chmod 755 ~/bin/sys_info_page sys_info_page</code> После запуска на экране должен появиться текст HTML-документа, потому что команды echo в сценарии посылают свои строки в стандартный вывод. Запустите программу снова и перенаправьте вывод программы в файл </html>sys_info_page.html</html>, чтобы затем посмотреть результат в веб-браузере (из консоли links):
sys_info_page > sys_info_page.html
links sys_info_page.html
Теперь, выполним небольшой рефакторинг кода. Текущая версия программы работает замечательно, но ее можно упростить. Если объединить все команды echo в одну, это определенно упростит в будущем добавление новых строк в вывод программы. Поэтому изменим программу, как показано ниже:
#!/bin/bash # Программа вывода страницы с информацией о системе echo "<html> <head> <title>Page Title</title> </head> <body> Page body. </body> </html>"
Строки в кавычках могут включать символы перевода строки и, соответственно, содержать несколько строк текста. Командная оболочка будет продолжать читать текст, пока не встретит закрывающую кавычку.
Это правило действует также в командной строке:
echo "<html> > <head> > <title>Page Title</title> > </head> > <body> > Page body. > </body> > </html>"
Символ <html»</html> в начале каждой строки – это приглашение к вводу командной оболочки, определяемое ее переменной PS2 (о приглашение к вводу, можно почитать в этой статье). Оно появляется всякий раз, когда происходит ввод многострочной инструкции.
Этап второй: добавление некоторых данных
Теперь, когда программа способна сгенерировать минимальный документ, добавим в отчет немного данных. Для этого внесите следующие изменения:
<html> <head> <title>System Information Report</title> </head> <body> <h1>System Information Report</h1> </body> </html>
Здесь добавлено название страницы и заголовок в теле отчета.
Переменные и константы
В нашем сценарии возникла проблема. Обратили внимание, что строка System Information Report повторяется дважды? Вообще, для такого крохотного сценария это не такая большая проблема, но представьте по-настоящему длинный сценарий, в котором эта строка повторяется много раз. Если в таком сценарии понадобится изменить название, придется внести изменения во множестве мест, а это масса ручной работы. Можно ли изменить сценарий так, чтобы строка определялась в нем только один раз? Это существенно упростило бы сопровождение сценария в будущем. Да, это возможно, например, так:
#!/bin/bash # Программа вывода страницы с информацией о системе TITLE="System Information Report For $HOSTNAME" echo "<html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> </body> </html>"
Создав переменную с именем TITLE и присвоив ей значение System Information Report, мы воспользовались преимуществами подстановки параметров и поместили строку во множество мест.
Название переменная подразумевает значение, которое может изменяться, и во многих приложениях переменные именно так и используются. Однако переменная TITLE в нашем приложении используется как константа. Константа, так же как переменная, имеет имя и содержит значение. Отличие лишь в том, что значение константы не изменяется.
Командная оболочка не различает константы и переменные; эти термины используются в основном
для удобства программиста. Типичное соглашение – использовать буквы верхнего регистра для обозначения констант и буквы нижнего регистра для истинных переменных.
<WRAP center round tip 99%>
Nota Bene!
В действительности командная оболочка имеет механизм, гарантирующий неизменяемость констант, в виде встроенной команды declare с параметром -r (read-only — только для чтения). Если переменной TITLE присвоить значение, как показано ниже:
declare -r TITLE=“Page Title”
Командная оболочка не допустит повторного присваивания значения переменной TITLE. Этот механизм редко используется на практике, но он имеется и его можно применять в особенно строгих сценариях. </WRAP>
Присваивание значений переменным и константам
Присваивание значений переменным производится так:
переменная=значение
Где переменная – это имя переменной, а значение – строка. В отличие от некоторых других языков программирования, командная оболочка не заботится о типах значений, присваиваемых переменным; она все значения интерпретирует как строки. Существует возможность заставить командную оболочку ограничить круг присваиваемых значений целыми числами, задействовав команду declare с параметром <html>-i</html>, но, как и объявление переменных, доступных только для чтения, эта возможность редко используется на практике.
Обратите внимание на отсутствие пробелов в операторе присваивания между именем переменной, знаком <html>=</html> и значением. А из чего может состоять значение? Из всего что угодно, что можно развернуть в строку
a=z # Присвоит переменной a строку "z". b="a string" # Внутренние пробелы должны находиться в кавычках. c="a string and $b" # При присваивании допускается выполнять подстановку, # например, значений других переменных. d=$(ls -l foo.txt) # Результат выполнения команды. e=$((5 * 7)) # Подстановка результата арифметического выражения. f="\t\ta string\n" # Экранированные последовательности, такие как # символы табуляции и перевода строки.
В одной строке можно выполнить присваивание сразу нескольким переменным:
a=5 b="a string $a"
При использовании подстановки имена переменных можно заключать в необязательные фигурные скобки <html>{}</html>. Это пригодится в том случае, когда имя переменной становится неоднозначным в окружающем контексте. В следующем примере выполняется попытка переименовать файл <html>myfile</html> в <html>myfile1</html> с использованием переменной:
filename="mylife" touch $filename mv $filename $filename1 mv: missing destination file operand after 'mylife' Try 'mv --help' for more information.
Эта попытка не увенчалась успехом, потому что командная оболочка интерпретировала второй аргумент команды mv как имя новой (и пустой) переменной. Ниже показано, как решается подобная проблема:
mv $filename ${filename}1
Добавив фигурные скобки, мы гарантировали, что командная оболочка не будет интерпретировать последний символ 1 как часть имени переменной.
Воспользуемся этой возможностью, чтобы добавить в отчет дополнительные данные, а именно дату и время составления отчета, а также имя пользователя, составившего отчет:
#!/bin/bash # Программа вывода страницы с информацией о системе TITLE="System Information Report For $HOSTNAME" CURRENT_TIME=$(date +"%x %r %Z") TIME_STAMP="Generated $CURRENT_TIME, by $USER" echo "<html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> </body> </html>"
Встроенные документы
Мы рассмотрели два разных метода вывода текста, и оба используют команду echo. Однако существует еще один, третий метод, который называется встроенным документом (here document), или встроенным сценарием (here script). Встроенный документ – это дополнительная форма перенаправления ввода/вывода, которая передает текст, встроенный в сценарий, на стандартный ввод команды. Действует это перенаправление так:
команда << индикатор
текст
индикатор
Где команда – это имя команды, принимающей указанный текст через стандартный ввод, а индикатор – это строка, отмечающая конец встроенного текста. Изменим сценарий, задействовав в нем встроенный документ:
#!/bin/bash # Программа вывода страницы с информацией о системе TITLE="System Information Report For $HOSTNAME" CURRENT_TIME=$(date +"%x %r %Z") TIME_STAMP="Generated $CURRENT_TIME, by $USER" cat << _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> </body> </html> _EOF_
Теперь вместо команды echo в сценарии используются команда cat и встроенный документ. На роль индикатора была выбрана строка _EOF_ (означает end-of-file — конец файла, распространенное соглашение), и она отмечает конец встроенного текста. Обратите внимание, что строка-индикатор должна находиться в отдельной строке, одна, и за ней не должно следовать никаких пробелов.
Но какие преимущества дало использование встроенного документа здесь? Практически никаких, кроме того, что кавычки внутри встроенных документов теряют свое специальное значение для командной оболочки.
Она интерпретирует их как обычные символы. Благодаря этому мы свободно вставляем кавычки во встроенные документы. Этим обстоятельством можно воспользоваться при разработке программ составления отчетов.