$ scriptbc −p 10 14600/7
2085.7142857142
Любому сценарию, читающему или записывающему данные в общий файл, например в файл журнала, необходим надежный способ блокировки файлов, чтобы другие экземпляры сценария не могли по ошибке затереть данные в файле до того, как он перестанет использоваться. Для этого часто создается отдельный файл-блокировка для каждого используемого файла. Наличие файла-блокировки играет роль семафора , или индикатора, сообщающего, что файл задействован другим сценарием и не должен использоваться. Запрашивающий сценарий в этом случае многократно проверяет наличие файла-блокировки, ожидая его удаления, после которого файл можно свободно использовать.
Однако применение файлов-блокировок сопряжено с большими трудностями, потому что многие решения, кажущиеся надежными, в действительности очень ненадежны. Например, для организации блокировки доступа к файлам часто используется следующее решение:
while [-f $lockfile]; do
··sleep 1
done
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
··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] Символы «EOF» должны находиться в начале строки, т. е. перед ними не должно быть пробелов. Это требование синтаксиса встроенных документов. В оригинале это правило нарушено. В данном листинге перед всеми строками добавлены 2 пробела, чтобы не нарушить отступы. Они к делу не относятся, и в данном случае считается, что метка EOF находится в начале строки, без отступа. — Примеч. пер .
Читать дальше