Многие реализации Unix, включая GNU/Linux и OS X, устанавливают утилиту lockfile по умолчанию. Ее присутствие в системе можно проверить простой командой man 1 lockfile. Если в результате откроется страница справочного руководства, значит, удача сопутствует вам! Сценарий в листинге 1.22 предполагает наличие команды lockfile, и все последующие сценарии требуют работоспособности механизма надежной блокировки, реализованного в сценарии № 10, поэтому перед их использованием также проверьте наличие команды lockfile в вашей системе.
Код
Листинг 1.22. Сценарий filelock
··#!/bin/bash
··# filelock — Гибкий механизм блокировки файлов
··retries="10"·········· # Число попыток по умолчанию
··action="lock"··········# Действие по умолчанию
··nullcmd="’which true’" # Пустая команда для lockfile
··while getopts "lur: " opt; do
····case $opt in
······l) action="lock";;
······u) action="unlock";;
······r) retries="$OPTARG";;
····esac
··done
··shift $(($OPTIND — 1))
··if [$# −eq 0]; then # Вывести в stdout многострочное сообщение об ошибке.
····cat << EOF >&2
······Usage: $0 [-l|-u] [-r retries] LOCKFILE
······Where −l requests a lock (the default), −u requests an unlock, −r X
······specifies a max number of retries before it fails (default = $retries).
··EOF[2]
····exit 1
··fi
··# Проверка наличия команды lockfile.
··if [-z "$(which lockfile | grep −v '^no ')"]; then
····echo "$0 failed: 'lockfile' utility not found in PATH." >&2
····exit 1
··fi
··if ["$action" = "lock"]; then
····if! lockfile -1 −r $retries "$1" 2> /dev/null; then
······echo "$0: Failed: Couldn't create lockfile in time." >&2
······exit 1
····fi
··else # Действие = разблокировка
····if [! -f "$1"]; then
······echo "$0: Warning: lockfile $1 doesn't exist to unlock." >&2
······exit 1
····fi
····rm −f "$1"
··fi
··exit 0
Как это работает
Как это часто бывает с хорошо написанными сценариями командной оболочки, половину листинга 1.22 занимает анализ входных данных и проверка на наличие ошибок. Затем выполняется инструкция if и осуществляется фактическая попытка использовать системную команду lockfile. Она вызывается с заданным числом попыток и генерирует собственное сообщение об ошибке, если ей так и не удалось заблокировать файл. А что произойдет, если предложить сценарию снять блокировку (например, удалить файл-блокировку), которой в действительности нет? В результате будет сгенерировано другое сообщение об ошибке. В противном случае lockfile просто удалит блокировку.
Если говорить более конкретно, первый блок использует мощную функцию getopts для анализа всех поддерживаемых флагов (-l, −u, — r) в цикле while. Это наиболее типичный способ использования getopts, который снова и снова будет встречаться в книге. Обратите внимание на команду shift $(($OPTIND — 1)) в строке : переменная OPTIND устанавливается функцией getopts, благодаря чему сценарий получает возможность сдвинуть входные параметры вниз (то есть значение параметра $2 сместится в параметр $1, например), вытолкнув тем самым обработанные параметры, начинающиеся с дефиса.
Поскольку этот сценарий использует системную утилиту lockfile, он сначала проверяет ее доступность в списке путей пользователя и завершается с сообщением об ошибке, если утилита недоступна. Далее следует простая условная инструкция , выясняющая, какая операция запрошена — блокировка или разблокировка, — и производится соответствующий вызов утилиты lockfile.
Запуск сценария
Сценарий filelock относится к категории сценариев, которые редко используются сами по себе, и для его проверки потребуется открыть два окна терминала. Чтобы установить блокировку, просто укажите имя файла, который будет играть роль блокировки, в аргументе сценария filelock. Чтобы снять блокировку, запустите сценарий еще раз с флагом −u.
Результаты
Сначала создадим заблокированный файл, как показано в листинге 1.23.
Листинг 1.23. Создание файла-блокировки командой filelock
$ filelock /tmp/exclusive.lck
$ ls −l /tmp/exclusive.lck
-r-r-r-··1 taylor··wheel··1 Mar 21 15:35 /tmp/exclusive.lck
Когда в следующий раз вы попытаетесь установить ту же блокировку, filelock выполнит указанное количество попыток (10 по умолчанию) и завершится с ошибкой (как показано в листинге 1.24):
2
Символы «EOF» должны находиться в начале строки, т. е. перед ними не должно быть пробелов. Это требование синтаксиса встроенных документов. В оригинале это правило нарушено. В данном листинге перед всеми строками добавлены 2 пробела, чтобы не нарушить отступы. Они к делу не относятся, и в данном случае считается, что метка EOF находится в начале строки, без отступа. —