4

I want to "list" all the files that are NOT open, within a certain directory using the GNU find command. Now, I am able to list the files that are open, but can't figure out a way to do the inverse of it.

find /my/dir/* -exec lsof {} \;  

Any ideas how this can be done?

puffadder
  • 143
  • 1
  • 4

2 Answers2

17
find /my/dir -type f | while read filename ; do fuser -s $filename || echo $filename ; done

This uses find just to generate a list of files. Then the while loop iterates over the list of results, for each result it runs fuser -s $filename which will exit with success if something is using the file.

The || echo $filename part means "if fuser failed (meaning nobody is using the file), echo the filename"

Ladadadada
  • 25,847
  • 7
  • 57
  • 90
stew
  • 9,263
  • 1
  • 28
  • 43
1

Here's what I use

$ find . ! -exec sudo fuser -s "{}" 2>/dev/null \; -exec echo {} \;

It uses two neat features of find:

  • execs are chained together, similarly to the bash operation &&. If the first exec returns a non-zero exit code then the second exec doesn't get invoked.
  • ! is an inverse operation for the exit code. fuser returns 1 for file not accessed, and 0 for file accessed, so we need to flip it to get what you want.

Note that I've added a sudo to fuser, so that it can find files opened by other users. Without this it will happily report that the file is not opened, while in reality it's just reporting that file is not opened by a process you have permission to monitor

Also worth mentioning - obviously calling fuser is more expensive than just checking the inode info, so if you have some other filters that you care about in addition to "is this an open file", you should apply those filters to the find first before doing the more expensive fuser check

Hamy
  • 367
  • 3
  • 11
  • instead of the `-exec echo {} \;` the `-print` action of find can be used e.g. `$ find . ! -exec sudo fuser -s "{}" 2>/dev/null \; -print` – squiddle Feb 13 '18 at 02:21