Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I need to swap filenames of two files (file and file_1). I'm using the following code for it.

mv file .phfile
mv file_1 file
mv .phfile file

This works but is very buggy, It sometimes even results in loss of data. Is there a better way to do this?

share|improve this question
5  
Something you should be aware of and fear - any program that has an open file handle to either one of those files will retain the open file handle after the rename because it's pointing to the same inode that it had when it originally opened the file. Until all programs that have the files open close them, this will be the case and cause data corruption if you expect that renaming them 'breaks' any existing writer handles. –  synthesizerpatel Feb 28 '12 at 1:08

3 Answers 3

There's no low-level way to swap files, so you need to use an intermediate temporary name. For robustness, make sure that the temporary name won't be used by any other program (so use mktemp) and that it's on the same filesystem as one of the files (otherwise the files would be needlessly copied instead of being just renamed).

swap_files () {
  tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
  mv -f -- "$1" "$tmp_name" &&
  mv -f -- "$2" "$1" &&
  mv -f -- "$tmp_name" "$1"
}
swap_files file file_1

Beware that if an error occurs, the first file could still be under its temporary name, and the second file may or may not have been moved yet. If you need robustness in case of interruptions and crashes, a variant with two temporary names may be easier to recover from.

swap_files2 () {
  tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  mv -f -- "$1" "$tmp_dir1/" &&
  mv -f -- "$2" "$tmp_dir2/" &&
  mv -f -- "$tmp_dir1/"* "$1" &&
  mv -f -- "$tmp_dir2/"* "$2" &&
  rmdir -- "$tmp_dir1" "$tmp_dir2"
}

If the temporary directories .swap_files.???????????? are present on a reboot, it means that a file swap was interrupted by a power failure. Beware that it's possible that one of the files has already been moved into place and the other one hasn't, so the code here doesn't take care of all cases, it depends what kind of recovery you want.

share|improve this answer
    
easy way indeed :D –  Kiwy Mar 2 at 8:15

This is more robust:

TMPFILE=tmp.$$
mv -- "$file1" $TMPFILE && mv -- "$file2" "$file1" && mv -- $TMPFILE "$file2"

quoting is for preventing problems with spaces in filenames, it uses a tmp file and && make the following command run only if the preceding ended successfully.

share|improve this answer
    
How's this? file1=1stfile && file2=2ndfile && temp="$(mktemp -dp /mnt/sdcard)" && mv "$file1" $temp && mv "$file2" "$file1" && mv $temp/"$file1" "$file2". It works. Thanks for your input. –  Binoy Babu Feb 28 '12 at 1:47
    
see this stackoverflow.com/q/9475497/1068546 –  Binoy Babu Feb 28 '12 at 3:04
    
using mktemp is good; nice find –  guido Feb 28 '12 at 3:10
    
but running a command with && in java with runtime.exec() don't work. :( –  Binoy Babu Feb 28 '12 at 3:15
    
you have to quote your yourShellInput variable: String yourShellInput = " \"echo hi && echo ho\" "; or if ouy have double quotes in your command String yourShellInput = " 'echo hi && echo ho' "; –  guido Feb 28 '12 at 3:33
up vote 0 down vote accepted

Here's what I ended up using :

file1=1stfile
file2=2ndfile
temp="$(mktemp -dp /mnt/sdcard)"
mv "$file1" $temp
mv "$file2" "$file1"
mv $temp/"$file1" "$file2"
share|improve this answer
    
I would add some checks that the mv statements succeeded, like tho other answers suggested. –  Walter A Mar 1 at 21:22
    
@WalterA That project is EOL now. I just added the answer for completion sake. Feel free to edit. –  Binoy Babu Mar 2 at 8:12

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.