Добавить в цитаты Настройки чтения

Страница 89 из 113

        </HEAD>

        <BODY>

                <H1>$TITLE</H1>

                <P>$TIME_STAMP</P>

                $(report_uptime)

                $(report_disk_space)

                $(report_home_space)

        </BODY>

</HTML>

_EOF_

Имена функций подчиняются тем же правилам, что и имена переменных. Функция должна содержать хотя бы одну команду. Команда return (которая является необязательной) помогает удовлетворить это требование.

Локальные переменные

В сценариях, что нам доводилось писать до сих пор, все переменные (включая константы) были глобальными. Глобальные переменные существуют и доступны в любой точке программы. В некоторых случаях это безусловно полезное свойство осложняет использование функций. Внутри функций иногда желательно использовать локальные переменные. Локальные переменные доступны только внутри функции, в которой они определены, и прекращают свое существование по завершении выполнения функции.

Поддержка локальных переменных позволяет программисту использовать переменные с именами, которые уже определены в сценарии, глобально или в других функциях, не беспокоясь о возможных конфликтах имен.

Следующий пример сценария демонстрирует, как определяются и используются локальные переменные:

#!/bin/bash

# local-vars: сценарий, демонстрирующий локальные переменные

foo=0   # глобальная переменная foo

funct_1 () {

        local foo         # переменная foo, локальная для funct_1

        foo=1

        echo "funct_1: foo = $foo"

}

funct_2 () {

        local foo         # переменная foo, локальная для funct_2

        foo=2

        echo "funct_2: foo = $foo"

}

echo "global:  foo = $foo"

funct_1

echo "global:  foo = $foo"

funct_2

echo "global:  foo = $foo"

Как видите, локальные переменные объявляются добавлением слова local перед именем переменной. В результате создается переменная, локальная по отношению к функции, в которой она определена. Когда выполнение выйдет за пределы функции, переменная перестанет существовать. Если запустить этот сценарий, он выведет следующее:

[[email protected]/* */ ~]$ local-vars

global:  foo = 0

funct_1: foo = 1

global:  foo = 0

funct_2: foo = 2

global:  foo = 0

Этот пример показывает, что присваивание значений локальной переменной foo внутри обеих функций не оказывает влияния на значение переменной foo, объявленной за пределами функций.

Эта особенность позволяет писать функции, сохраняя их независимость друг от друга и от сценария, в котором они определяются. Это очень ценное качество, оно предотвращает взаимовлияние разных частей программы друг на друга, а кроме того, помогает писать переносимые функции, то есть функции, которые можно скопировать из одного сценария в другой.

Постоянное опробование сценария

В процессе разработки программ необходимо постоянно проверять их работоспособность. Запуская и тестируя программы как можно чаще, мы сможем выявить ошибки на самых ранних этапах разработки. Это существенно упрощает задачу отладки. Например, если после внесения небольших изменений и очередного запуска программы обнаружится ошибка, источник проблемы почти наверняка будет находиться в последних изменениях. Добавив пустые функции, которые на языке программистов называются заглушками, мы смогли проверить работоспособность программы на ранней стадии. Создавая заглушку, неплохо было бы включить в нее что-то, что давало бы обратную связь, позволяющую программисту оценить ход выполнения. Если сейчас взглянуть на вывод нашего сценария, можно заметить несколько пустых строк, следующих за строкой с текущим временем, но мы пока не уверены в причинах их появления.

[[email protected]/* */ ~]$ sys_info_page

<HTML>

        <HEAD>

                <TITLE>System Information Report For twin2</TITLE>

        </HEAD>

        <BODY>

                <H1>System Information Report For linuxbox</H1>

                <P>Generated 03/19/2012 04:02:10 PM EDT, by me</P>

        </BODY>

</HTML>

Изменим функции, добавив в них сообщения для обратной связи:



report_uptime () {

        echo "Function report_uptime executed."

        return

}

report_disk_space () {

        echo "Function report_disk_space executed."

        return

}

report_home_space () {

        echo "Function report_home_space executed."

        return

}

И запустим сценарий еще раз:

[[email protected]/* */ ~]$ sys_info_page

<HTML>

        <HEAD>

                <TITLE>System Information Report For linuxbox</TITLE>

        </HEAD>

        <BODY>

                <H1>System Information Report For linuxbox</H1>

                <P>Generated 03/20/2012 05:17:26 AM EDT, by me</P>

                Function report_uptime executed.

                Function report_disk_space executed.

                Function report_home_space executed.

        </BODY>

</HTML>

Теперь можно с уверенностью сказать, что наши три функции выполняются как надо.

Теперь, когда каркас функций готов и работает, самое время добавить в них некий код. Сначала займемся функцией report_uptime:

report_uptime () {

        cat <<- _EOF_

                <H2>System Uptime</H2>

                <PRE>$(uptime)</PRE>

                EOF_

        return

}

Она выглядит очень просто. Мы использовали встроенный документ для вывода заголовка раздела и результатов выполнения команды uptime, заключив их в теги <PRE>, чтобы сохранить формат вывода команды. Функция report_disk_space выглядит аналогично:

report_disk_space () {

        cat <<- _EOF_

                <H2>Disk Space Utilization</H2>

                <PRE>$(df -h)</PRE>

                _EOF_

        return

}

Она получает информацию о дисковом пространстве с помощью команды df -h. Наконец, определим функцию report_home_space:

report_home_space () {

        cat <<- _EOF_

                <H2>Home Space Utilization</H2>

                <PRE>$(du -sh /home/*)</PRE>

                _EOF_

        return

}

Для решения поставленной задачи мы использовали команду du с параметрами -sh. Однако это не полное решение задачи. Даже при том, что его можно использовать в некоторых системах (например, в Ubuntu), кое-где оно работать не будет. Причина в том, что во многих системах для домашних каталогов выбираются разрешения, не позволяющие читать их содержимое другим пользователям, что является вполне разумной мерой предосторожности. В этих системах функция report_home_space в том виде, в каком она написана здесь, будет работать, только если запустить сценарий с правами суперпользователя. Лучшее, что можно сделать в такой ситуации, — корректировать поведение сценария в соответствии с привилегиями пользователя, запустившего его. Мы займемся этим в главе 27.

функции командной оболочки в файле .BASHRC

Функции командной оболочки могут служить прекрасной заменой псевдонимам и в действительности считаются предпочтительным способом определения небольших команд для личного использования. Возможности псевдонимов весьма ограниченны в отношении использования некоторых видов команд и особенностей командной оболочки, тогда как функции позволяют все, что можно выразить в виде сценария. Например, если вам понравилась функция report_disk_space, созданная нами для нашего сценария, вы можете создать похожую функцию с именем ds в своем файле .bashrc: