I am trying to write a find command that finds both files and directories, the issue is that I get only files or an error depending on certain variables in the command.

This command outputs nothing at all:

find '/mnt/downloads/cache/' -depth -mindepth 1 \( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty \) -print

This is because the two filters are not encapsulated in ( ). Why are double quotes needed?

This command outputs files only but not directories:

find '/mnt/downloads/cache/' -depth -mindepth 1 \( \( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty \) \) -print

Extra set of brackets encapsulating the two arguments is the only difference.

The last variation of the command results in an error:

find '/mnt/downloads/cache/' -depth -mindepth 1 \( \( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty {} \) \) -print

find: paths must precede expression: {}

Why does adding a second set of {} after diretory test results in this error?

Fixed command:

find "/mnt/downloads/cache" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) \
  • 1
    Umm - doesn't it output twice because you are using both -print and -exec echo {} ? Why would you put the extra {} after -empty? AFAIK it doesn't take an argument, so that's why {} is being parsed as a misplaced path. Dec 9 '17 at 13:43
  • @steeldriver You are right about print / echo, I though I had removed it. Edited question to remove that part. So you are saying that the {} is an argument of exec only and type d / f doesn't need {}? If so why am I still not getting directories in the output? Feel free to add it as an answer as I can't accept a comment no matter how correct it is :)
    – DominicM
    Dec 9 '17 at 13:52

Since the implied and (-a) has higher precedence than the -o, the right hand side of the -o in the first expression is taken as one unit with regard to the or operation, i.e. this:

\( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty \) -print

acts the same as this:

\( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty -print \)

So for files, it runs fuser, and for directories it prints their names.

The second:

\( \( -type f ! -exec fuser -s {} \; \) -o \( -type d -empty \) \) -print

has explicit parenthesis, but you don't need the inner ones, this is equal:

\( -type f ! -exec fuser -s {} \;  -o  -type d -empty  \) -print

And it should print all empty directories and files for which fuser returns a falsy value (!= 0, inverted by the !).

In the third you have ... -empty {} ..., where the {} is taken as path name, and the error message tells what the issue is.

  • Ahh, what I wanted is ! -empty, I missed the not operator...
    – DominicM
    Dec 9 '17 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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