Подстановки # и % полезны, например, тогда, когда нужно «выкусить» из полного пути к файлу собственно его имя или, наоборот, родительский каталог:
$ path=`which twm`; echo $path
/usr/X11R6/bin/twm
$ echo ${path##*/}
twm
$ echo ${path%/*}
/usr/X11R6/bin
$
8.6. Функции
Оператор определения функции имеет следующий синтаксис:
[function] имя() {
список
}
Определять функцию можно в любом месте сценария, но вызов ее должен осуществляться строго после описания. Вызывается функция подобно любой команде — по имени. Переданные ей аргументы в теле функции рассматриваются как позиционные параметры, причем в вызывающем сценарии значения позиционных параметров не меняются. Значение позиционного параметра 0 — это имя функции.
Вызов функции не порождает нового процесса, поэтому ей видны локальные переменные, установленные вызывающим сценарием или оболочкой до ее вызова.
Ошибка при выполнении функции приводит к немедленному ее завершению с ненулевым кодом возврата. Если вы хотите передать в коде возврата собственное значение, пользуйтесь оператором return <число>. Отсутствие числа или всего оператора return означает возврат нулевого значения. Код возврата функции помещается в переменную $? и доступен до выполнения следующей команды.
Если вы задумали функцию как «библиотечную» (вызываемую из разных сценариев и в связи с этим определенную в отдельном файле), то для того, чтобы определить ее в текущем процессе, нужно не запускать ее файл на выполнение, а прочитать его встроенной командой source.
8.7. Обработка сигналов и протоколирование
Обычно при завершении сеанса работы пользователя система посылает всем запущенным им процессам сигналы (п.3.3.2), которые приводят к прекращению этих процессов. Возможно, вам понадобится обеспечить своему сценарию возможность продолжать выполнение даже после отключения запустившего его пользователя. Тогда посланный сигнал придется перехватывать и обрабатывать собственными средствами сценария.
Перехватить сигнал можно с помощью встроенной команды trap. Формат ее следующий:
trap [-lp] [команда сигнал сигнал...]
Ключ -l выводит список имен и номеров сигналов, известных в ОС Linux. Ключ -p выводит список команд, связанных с каждым сигналом. Сигналы указываются по номерам или именам, приставку SIG можно опускать.
Команда — это та команда, которая будет выполнена оболочкой при получении сигнала (ваш собственный обработчик). Если вместо нее указать пустую строку, то перечисленные сигналы будут проигнорированы. Если вместо сигналов указать EXIT или 0 (фиктивный номер), то команда будет выполнена при завершении сеанса работы с оболочкой.
Чаще всего перехватываются сигналы:
01 SIGHUP hangup, освобождение линии связи;
02 SIGINT interrupt, прерывание;
03 SIGQUIT quit, выход;
15 SIGTERM terminate, программный сигнал завершения.
Чтобы игнорировать все эти сигналы, введите команду:
$ trap '' 1 2 3 15
Протоколировать работу собственного сценария можно двумя способами.
Первый состоит в использовании команды-фильтра tee (п.3.4.6). Название этой команды происходит от английского названия буквы T, и действие ее похоже на эту букву: она копирует данные из своего стандартного потока ввода и раздваивает их на стандартный поток вывода и поток в указанный файл:
$ LOGFILE=my_log
$ if [ '$LOGGING' == 'true' ]; then
> my_script | tee $LOGFILE; else
> my_script;
> fi
$
Если вы собираетесь не вводить эти команды из командной строки, а включить их в сценарий my_script, то вызов сценария изнутри него самого должен выглядеть так:
exec $0
Встроенная команда exec заменяет текущий процесс (то есть ту дочернюю оболочку, в которой запущен сценарий) на выполняемую команду, и сценарий, завершившись, возвращает управление прямо родительской оболочке. Интерактивную оболочку (ту, с которой вы начинаете сессию) подменить таким образом нельзя.
Если команде exec не указан аргумент, но указано перенаправление ввода- вывода, то exec совершает это перенаправление, продолжая выполнение текущего сценария. Таким способом можно получить динамическое перенаправление:
$ tty
/dev/pts/2
$ echo 'Вывожу строку на терминал'
Вывожу строку на терминал
$ exec > log
$ echo 'Вывожу строку в файл'
$ echo 'И эту в файл'
$ exec > /dev/pts/2
$ echo 'А эту снова на терминал '
А эту снова на терминал
$
Второй способ заключается в использовании команды script, которая копирует в файл весь сеанс работы в текстовой консоли: ввод пользователя и вывод команд. Это должен быть в полном смысле слова сеанс работы в командной строке: полноэкранные команды, такие, как редактор vi и даже man, оставляют в файле протокола мусор. Если вы запускаете команду script вручную, то остановить протоколирование можно командой exit.
$ LOGFILE=my_log
$ if [ '$LOGGING' == 'true' ]; then
