touch $lockfile
Кажется, что такое решение должно работать. Или нет? Сценарий в цикле проверяет присутствие файла-блокировки и, как только он исчезает, тут же создает собственный, чтобы в безопасности изменить рабочий файл. Если в это время другой сценарий увидит файл-блокировку, то продолжит выполнять цикл ожидания, пока тот не исчезнет. Однако на практике такой способ не работает. Представьте, что сразу после выхода из цикла while, но перед вызовом команды touch диспетчер задач приостановит сценарий, дав возможность поработать другому сценарию.
Если вам непонятно о чем речь, вспомните, что хотя кажется, что компьютер делает что-то одно, в действительности он выполняет сразу несколько программ, переключаясь между ними через короткие интервалы времени. Проблема в том, что между завершением цикла, проверяющего существование файла-блокировки, и созданием нового проходит время, в течение которого система может переключиться с одного сценария на другой, а тот в свою очередь благополучно убедится в отсутствии файла-блокировки и создаст свою версию. Затем система переключится на первый сценарий, который тут же выполнит команду touch. В результате оба сценария будут считать, что имеют исключительный доступ к файлу-блокировке, то есть сложится ситуация, которой мы пытаемся избежать.
К счастью, Стефан ван ден Берг (Stephen van den Berg) и Филип Гюнтер (Philip Guenther), авторы программы procmail для фильтрации электронной почты, также создали утилиту командной строки lockfile, которая дает возможность безопасной и надежной работы с файлами-блокировками в сценариях командной оболочки.
Многие реализации 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
····case $opt in
······l) action="lock";;
······u) action="unlock";;
······r) retries="$OPTARG";;
····esac
··done
··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.
····echo "$0 failed: 'lockfile' utility not found in PATH." >&2
····exit 1
··fi
····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
Как это работает