Summary of Answers: while literature promotes "-execdir" as safer than "-exec", do not ignore the operational difference. The former is not a simple reimplementation of the latter. Also, when using find specifically for interactive removals, executing "rm -f" via the "-okdir" option is also viable. Similarly for slightly more complicated constructs.
I'm trying to learn the "find" command, and I'm having trouble understanding its output. I apologize if this is a duplicate, but the problem statement is a little convoluted and hard to Google.
Let me set up a pet case: I start in some directory (".") with two subdirectories "A" and "B". In both of these, there is a file named "hello.c."
So, for example,
find . -name "hello.c"
would print like so:
./A/hello.c
./B/hello.c
So far so good. What I get lost on is when I try to do something with the "-execdir" option; let's say I want to use an interactive removal. Then:
find . -name "hello.c" -execdir rm -i {} \;
or similar. What I expect is
rm: remove regular file "./A/hello.c"?
and then, answering that, a similar prompt for the "hello.c" in directory "B."
What actually appears, unfortunately, is
rm: remove regular file "./hello.c"?
In this tiny example, I can reasonably infer that it's asking about "./A/hello.c", but if one scales this example up then you get dozens of files that all have their pathnames truncated to "./". And I cannot differentiate between dozens of "./hello.c"s, not without a bearing on which subdirectory they each live in.
So, my question boils down to a desire to print fuller pathnames via "-execdir." Could I hear a hint as to what sublety in the manpage escaped me? Little is said about the "{}" substitution. Or if there is some better way to manage this particular case (interactive removal), I should like to hear that too, because I'm not sure my approach is best practice.
Best Answer
The man page for GNU
find
describes-execdir
in part thusly:So there is no real subtlety involved.
-exec
invokes the command from the directory that you runfind
from (and thus needs to provide the path either relative to that directory or absolute from the root), and-execdir
invokes the command from the directory containing the file and thus doesn't need to provide the full path, so does not.To get the behavior you are after, you should use
-exec
rather than-execdir
.You can demonstrate this behavior by replacing your
rm
invocation with for exampleecho
to simply print the list of parameters (in this case, the file name). Or use-print
which does that without needing to invoke an external command. (Note:-print
is also the default action if none is given.)If you didn't need the confirmation, you could have used
-delete
instead. For large number of files that is also likely to be more efficient as it avoids having to invokerm
time and time again.