Другой вариант - использовать параметр оболочки noclobber
, запустив set -C
. Тогда >
потерпит неудачу, если файл уже существует.
Вкратце:
set -C
lockfile="/tmp/locktest.lock"
if echo "$$" > "$lockfile"; then
echo "Successfully acquired lock"
# do work
rm "$lockfile" # XXX or via trap - see below
else
echo "Cannot acquire lock - already locked by $(cat "$lockfile")"
fi
Это заставляет оболочку вызывать:
open(pathname, O_CREAT|O_EXCL)
, который атомарно создает файл или завершается ошибкой, если файл уже существует.
Согласно комментарию к BashFAQ 045 , это может произойти сбой в ksh88
, но оно работает во всех моих оболочках:
$ strace -e trace=creat,open -f /bin/bash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3
$ strace -e trace=creat,open -f /bin/zsh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_LARGEFILE, 0666) = 3
$ strace -e trace=creat,open -f /bin/pdksh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_LARGEFILE, 0666) = 3
$ strace -e trace=creat,open -f /bin/dash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3
Интересно, что pdksh
добавляет флаг O_TRUNC
, но, очевидно, он избыточен:
либо вы создаете пустой файл, либо ничего не делаете.
То, как вы делаете rm
, зависит от того, как вы хотите обрабатывать нечистые выходы.
Удалить при чистом выходе
Новые запуски не выполняются до тех пор, пока не будет устранена проблема, вызвавшая нечистый выход и файл блокировки удален вручную.
# acquire lock
# do work (code here may call exit, etc.)
rm "$lockfile"
Удалить на любом выходе
Новые запуски выполняются успешно, если скрипт еще не запущен.
trap 'rm "$lockfile"' EXIT