I have the following problem. I have two directories which I'll refer to as dir1 and dir2. They are both populated with both files and subdirectories. They are both on the same filesystem. The contents of dir1 is old, and must be replaced with the contents of dir2. The contents of dir1 can be discarded. However, I need this replacing to happen atomically. My current solution is the following.
mv dir1 dir1_backup; mv dir2 dir1; rm -rf dir1_backup
If the first command fails, the second command will not run. This is good. However, what if the second command fails? dir1 does not exist anymore, and I'm left in an invalid state.
What is the best way to accomplish this? Is it possible?
Linux provides the renameat2
system call which with the RENAME_EXCHANGE
flag will swap 2 objects:
renameat2(AT_FDCWD, "dir1", AT_FDCWD, "dir2", RENAME_EXCHANGE);
I don't think that your assertion above that the second command will fail if the first fails is true. If mv dir1 dir1_backup
fails, then dir1 will still exist, and mv dir2 dir1
will make dir2 a subdirectory of dir1. Also, since you are passing -f
to rm
in the third command, it will silently fail to delete a non-existant directory.
For reference, three bash operators (assuming bash here) and what they do:
If you want each command's execution to be dependent upon the previous command's successful execution, then you might want to consider something like the following:
mv dir1 dir1_backup && mv dir2 dir1 && rm -rf dir1_backup
If the moving of a directory is a failure mode you expect, then it may be reasonable to test the return value of the move or to test for the existence of the expected directory before proceeding to remove the old directory contents. If the test fails, then move the old directory contents back. The overall operation will have failed, but at least you will not be in an invalid state. For example:
mv dir1 dir1_backup && \
mv dir2 dir1 && \
rm -rf dir1_backup || mv dir1_backup dir1
Since we know that &&
executes the following command only if the previous command exits successfully, mv dir2 dir1
will only execute if mv dir1 dir1_backup
succeeds.
Further, rm -rf dir1_backup
will only execute if the move of dir2 to dir1 succeeds. However, if the last exit code (the code returned by mv dir2 dir1
if it has failed) is non-zero, the ||
operator causes mv dir1_backup dir1
to execute.
Hope that helps! Let me know if it needs clarification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With