Я хотел бы знать, есть ли способ переместить файл только в том случае, если место назначения не существует - другими словами, перемещать только в том случае, если это не приводит к перезаписи.
mv --update
казалось первым решением, однако, если метка времени исходного пути новее, чем место назначения, move перезапишет ее, и все попытки обойти это путем изменения метки времени до того, как перемещение завершится ошибкой.
Мне нужно это поведение для реализации простой блокировки на основе файла, где наличие файла блокировки указывает на то, что блокировка получена.
Если вы находитесь в одной файловой системе, используйте link()
и unlink()
вместо того mv
:
$ touch src
$ ln src dest && rm src
$ ls
dest
$ touch src2
$ ln src2 dest && rm src2
ln: creating hard link `dest': File exists
$ ls
dest src2
Вы можете использовать rsync с --ignore-existing
переключатель:
skip updating files that exist on receiver
Однако я думаю, что это не атомарно. Вы можете создать консультативный замки с flock
чтобы убедиться, что процессы ты контролируешь (Сотрудничающие процессы) не будут писать ему. Но другой процесс все же мог.
Единственный способ заблокировать файл без риска того, что другой процесс вмешается в него, - это смонтировать файловую систему с обязательной блокировкой. Из <linux_kernel_source>/Documentation/filesystems/mandatory-locking.txt
:
Что такое обязательная блокировка?
Обязательная блокировка - это принудительная блокировка файлов в ядре, в отличие от более обычной совместной блокировки файлов, используемой для обеспечения последовательного доступа к файлам между процессами. Блокировки файлов применяются с помощью системных вызовов flock () и fcntl () (и библиотечной подпрограммы lockf (), которая является оболочкой для fcntl ()). Обычно процесс проверки блокировок файла, который он хочет update, прежде чем применить собственную блокировку, обновить файл и снова разблокировать его. Наиболее часто используемый пример этого (а в случае sendmail - самый проблемный) - доступ к почтовому ящику пользователя. Почтовый пользовательский агент и агент передачи почты должны защищать почтовый ящик от одновременного обновления и предотвращать чтение почтового ящика во время его обновления.
В идеальном мире все процессы будут использовать и соблюдать кооперативную или «рекомендательную» схему блокировки. Однако мир несовершенен, и есть много плохо написанного кода.
Из man-страницы open (2):
Переносимые программы, которые хотят выполнять атомарную блокировку файлов с помощью файла блокировки и которым необходимо избегать поддержки NFS для O_EXCL, могут создавать уникальный файл в той же файловой системе (например, с включением имени хоста и PID) и использовать ссылку (2) для сделайте ссылку на файл блокировки. Если ссылка (2) возвращает 0, блокировка успешна. В противном случае используйте stat (2) для уникального файла, чтобы проверить, увеличилось ли его количество ссылок до 2, и в этом случае блокировка также успешна.