3

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.

5

The man page for GNU find describes -execdir in part thusly:

Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find.

So there is no real subtlety involved. -exec invokes the command from the directory that you run find 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 example echo 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 invoke rm time and time again.

  • Oh my. I read that, too, but I glossed over it because my brain just didn't parse it for some reason. Thank you for your answer. – Kalvin Lee Dec 16 '14 at 9:19
2

To have the security benefit of -execdir (which is really about making sure the command doesn't get a path with several components) and get a prompt, you can use:

find . -name hello.c -okdir rm -f {} \;

(note that at least the GNU implementation of find doesn't escape filenames in a way suitable for terminals as GNU rm does (wrt control, newline, unprintable characters...)).

1

Instead of using -exec, which is simpler but less secure, you could just print the working directory. e.g.

-execdir sh -c 'pwd ; rm -i "$1"' . {} \;

Alternatively, print the whole path with

-execdir sh -c 'readlink -e "$1" ; rm -i "$1"' . {} \;
  • @StéphaneChazelas I fixed the quotes, but what did you mean with not embedding {} as shell code? Are you talking about the first line? And why? – Sparhawk Dec 16 '14 at 20:47
  • @Sparhawk what if the filename is "; rm -rf /"? – Random832 Dec 16 '14 at 21:09
  • @Random832 Ah okay. So is any attempt to run multiple commands within an -exec or -execdir block inherently insecure? Perhaps I should ask this as another question. – Sparhawk Dec 16 '14 at 21:12

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.