我想知道是否只有在目的地不存在的情况下才能移动文件 - 换句话说,只有在不会导致覆盖时才移动。
mv --update
似乎首先是解决方案,但是,如果源路径的时间戳比目标更新,则move将覆盖它,并且所有通过在移动之前修改时间戳来避免这种情况的尝试都将失败。
我需要这种行为来实现一个简单的基于文件的锁,其中“lock”文件的存在表明已获取锁。
我使用perl执行此任务,因此如果perl具有此功能,则会有所帮助。但是,我需要确保移动操作是原子的。
答案 0 :(得分:7)
但是当别人有锁时你会怎么做?退出并稍后再试?忙等待?
如果您不需要同步,那么设置O_EXCL
和O_CREAT
标志的sysopen
是一个不错的选择,只有当文件不存在时才会创建该文件。
use Fcntl qw/ :DEFAULT /;
# ...
sysopen my $fh, $LOCKFILE, O_EXCL|O_CREAT
or die "$0: sysopen: $!";
但请注意Linux open(2)
手册页中的以下警告:
只有在内核2.6或更高版本上使用NFSv3或更高版本时,才支持
O_EXCL
。在未提供NFSO_EXCL
支持的环境中,依赖它执行锁定任务的程序将包含竞争条件。想要使用锁文件执行原子文件锁定并且需要避免依赖O_EXCL
的NFS支持的可移植程序可以在同一文件系统上创建一个唯一的文件(例如,包含主机名和PID),并使用link(2)
建立到锁文件的链接。如果link(2)
返回0,则锁定成功。否则,在唯一文件上使用stat(2)
检查其链接计数是否已增加到2,在这种情况下锁定也是成功的。
“我宁愿拥有一个网络文件系统而不是NFS”,俗话说,如果可以的话,请将协调进程保留在同一台机器上。
您可以考虑使用以下代码中的flock
:
#! /usr/bin/perl
use warnings;
use strict;
use Fcntl qw/ :DEFAULT :flock /;
my $LOCKFILE = "/tmp/mylock";
sub acquire_lock {
sysopen my $fh, $LOCKFILE, O_RDWR|O_CREAT or die "$0: open: $!";
flock $fh, LOCK_EX or die "$0: flock: $!";
$fh;
}
sub work {
for (1 .. 2) {
my $fh = acquire_lock;
print "$0: $$ has lock\n";
sleep rand 3;
close $fh or warn "$0: [$$] close: $!";
}
exit;
}
对于演示,下面的代码会分叉五个孩子轮流获取锁定:
my $KIDS = 5;
my %pids;
for (1 .. $KIDS) {
my $pid = fork;
die "$0: fork: $!" unless defined $pid;
$pid ? ++$pids{$pid} : work;
}
while (my $pid = wait) {
last if $pid == -1;
warn "$0: unknown child $pid" unless delete $pids{$pid};
}
warn "$0: still alive: " .
join(", " => sort { $a <=> $b } keys %pids) .
"\n"
if keys %pids;
示例输出:
./kidlock: 26644 has lock ./kidlock: 26645 has lock ./kidlock: 26646 has lock ./kidlock: 26645 has lock ./kidlock: 26648 has lock ./kidlock: 26646 has lock ./kidlock: 26647 has lock ./kidlock: 26647 has lock ./kidlock: 26644 has lock ./kidlock: 26648 has lock
答案 1 :(得分:0)
mv -n
应该做你想做的事。
从手册页:
-n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)
答案 2 :(得分:0)
perldoc -f
rename
在* NIX系统上,rename
是原子的,并且满足您提出的问题/要求。但是,作为锁定文件的惯例,我经常使用@gbacon的answer中建议的O_EXCL|O_CREAT
方法。
答案 3 :(得分:0)
注意如果你使用Greg解决方案,如果另一个程序试图打开它,则这两个指令之间可能存在竞争条件。
sysopen my $fh, $LOCKFILE, O_RDWR|O_CREAT or die "$0: open: $!";
flock $fh, LOCK_EX or die "$0: flock: $!";