It seems mv -T
is a GNU extension to mv
.
Is there a robust way (race-free, portable, and otherwise without "gotchas") to do the equivalent of mv -T dir1 dir2
?
To be clear:
I DO NOT want this to ever result in
dir2/dir1
. Ifdir2
exists, I want the command to fail. Ifdir1
is moved at all, it must becomedir2
.I DO NOT want to move out every child one-by-one. I want to move the directory itself.
I DO want to avoid race conditions. It's trivial to test if
dir2
exists first, but then it might be created after the check but before the move.
dir2
exists, I want the command to fail" portably; POSIX requiresrename
to delete an empty dir2 and succeed. – Michael Homer Feb 26 '19 at 03:37renameat
. I don't believe there can be any portable method to rename a file that does not go through that path. Given that, which of your requirements can you relax? What sorts of race condition are you concerned with? – Michael Homer Feb 26 '19 at 03:41dir1
landing insidedir2
, which can happen if multiple processes try to run this command at once. However, I guess it would be fine if an emptydir2
were deleted. Would that help? Also, if there's still no single POSIX solution, I'd be interested in knowing if there are even platform-specific solution that I can call. E.g. is there a solution that works on Mac, let alone other platforms? I haven't found any. – user541686 Feb 26 '19 at 03:54renameat2
system call takes a flag argument and one such flag isRENAME_NOREPLACE
which causes it to: "Don't overwrite newpath of the rename. Return an error if newpath already exists." ... But that doesn't really satisfy "portable", so not sure it solves your problem... – filbranden Feb 26 '19 at 04:47mv -T
... – user541686 Feb 26 '19 at 04:58mv -T
is actually prone to a race too? Or does it use another technique? – user541686 Feb 26 '19 at 05:06mv -T
usesrenameatu
, which has a race condition (by design in order not to fail eagerly), yes. I don't think it's possible not to have one at all, but you can minimise the risk (for some systems at least). If the issue is when "multiple processes try to run this command at once", can't standard locking in "this command" do the job? – Michael Homer Feb 26 '19 at 06:22dir2
is in effect a lock file: ifmkdir dir2
succeeds, that means you uniquely, atomically created it, and thenrename
can do its job of replacing it. The problem becomes accessingrename
, which I don't think you can do from Bash, but luckily this isn't a [tag:bash] question. This question does list some ways of running library functions from the shell, though. There are still other race conditions: someone could make a file inside the directory in between, or rename a parent directory, or change a symlink... – Michael Homer Feb 26 '19 at 07:17