Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to move files in a directory that are not currently in use. I have a sense that some combination of lsof, find, and xargs could work but I can't quite get there. So far, I created the following command:

lsof mydir/*|awk '(NR>1){print $9}

This gives me a list of files that ARE being used. If I could just get a list of files that are NOT being used, then something like xargs could issue a mv on those files. I just can't seem to find an elegant way of doing this. Does anyone have any hints for me?

share|improve this question

migrated from Dec 8 '10 at 1:18

This question came from our site for professional and enthusiast programmers.

This seems like a question for Super User or Unix and Linux – Michael Mrozek Dec 7 '10 at 17:53
You might have to break out the big guns, and script in python and perl to parse the lsof output into a map, and then do the walk operation, excluding opened files, to build up the list of files to move. However I wonder why you can't just move all files in the first place? – Douglas Leeder Dec 7 '10 at 17:54
Another idea might be to move everything, then move anything open back to the original location? Assuming the move preserves enough information of course. – Douglas Leeder Dec 7 '10 at 17:55
@Michael Mrozek: Why? This is a programming question. I'm not asking how to use ls, I'm trying write a bash script. – User1 Dec 7 '10 at 17:56
@User1 That shouldn't be true; you can move a file around and open file handles will still work. You can even erase a file and programs that have it open can keep reading from it – Michael Mrozek Dec 7 '10 at 18:02

I'd do it this way.

find $dir -maxdepth 1 | sort > $other_dir/all_files
lsof $dir/* | awk '(NR>1) {print $9}' | sort > $other_dir/in_use_files
comm -2 -3 $other_dir/all_files $other_dir/in_use_files

From comm(1):

       comm - compare two sorted files line by line

       comm [OPTION]... FILE1 FILE2


       -2     suppress lines unique to FILE2

       -3     suppress lines that appear in both files

Now it's a simple matter of reformatting into a series of mv statements. Perhaps like this:

while IFS= read file ; do
    mv "$file" "$destination/"
done < <(comm -2 -3 all_files in_use_files)

Or using another intermediate file if you prefer.

share|improve this answer
Thanks for the tip about using comm that puts everything together. – User1 Dec 7 '10 at 19:59

Perhaps not the best way, but one can just code it up in a few minutes:

get your list of open files (sort if not already)

get a list of all files (sort if not already)

diff the two lists

xargs whatever

The number of steps here will make obvious something that should have been a concern anyway, which is race conditions - the files that are in use when you select them may not be the files that are in use when you actually move them.

share|improve this answer
Great point about race conditions. – Wesley Rice Dec 7 '10 at 18:36
up vote 2 down vote accepted

Thanks to @Sorpigal's suggestion, I found an easy way to make this work without loops:

comm -2 -3 <(find $dir -maxdepth 1 -type f|sort) <(sudo lsof $dir/* | awk '(NR>1) {print $9}'|sort) | xargs -I {} mv {} $move_dir

I'm not sure of race conditions but it doesn't matter in my case. The files are opened once for writing and then should be closed until moved.

share|improve this answer

It's what fuser is meant for.

$ fuser access.log
/var/log/apache2/access.log: 2132 15456 16414 19555 19622
$ fuser access.log 2>/dev/null
 2132 15456 16414 19555 19622
$ if [ ! -z "$(fuser access.log 2>/dev/null)" ]
> then
>   echo "this file is in use"
> else
>   echo "this file is not in use"
> fi
this file is in use
share|improve this answer

Your Answer


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.