0

The following command

mkdir -p /tmp/test/foo /tmp/test/bar && \
find /tmp/test/ -mindepth 1 -type d \
-exec echo Deleting "{}" \; \
-exec rm -rv "{}" \;

I'd expect to print

Deleting /tmp/test/foo
removed directory '/tmp/test/foo'
Deleting /tmp/test/bar
removed directory '/tmp/test/bar'

(per 1st -exec statement) and delete respective directories (per 2nd -exec statement). Well, technically this is indeed what's happening and being printed on stdout - but there're 2 additional lines on stderr.

Deleting /tmp/test/foo
removed directory '/tmp/test/foo'
find: ‘/tmp/test/foo’: No such file or directory
Deleting /tmp/test/bar
removed directory '/tmp/test/bar'
find: ‘/tmp/test/bar’: No such file or directory

So it /seems/ the 2nd -exec-statement calling rm -rv is issued twice.

  • Why / What's exactly happening here?
  • How do I achieve what I'd actually expect from above command?
1
  • You are deleting directories and find is wanting to enter the directories to see if there is any work to be done in them. Add a -depth flag to do a depth-first walk of the tree? Commented Feb 9, 2023 at 23:58

1 Answer 1

4

TL;DR

You are being confused by warning messages from find which look similar to error messages from rm into thinking that rm is being invoked multiple times per directory when it is not. Adding a -depth to the find command will stop the warnings and give the expected output.

Explanation

It would be clearer if you had a slightly more complicated directory structure. You currently have

$ tree /tmp/test
/tmp/test
├── bar
└── foo

but if you had say

/tmp/test
├── bar
└── foo
    └── wibble
        └── hello.txt

then you can see that your example find command doesn't really make a lot of sense. The order that files are found within a directory is not defined, but let us assume that it finds foo first and then bar. The command will first remove the foo subtree, so will remove /tmp/test/foo/wibble/hello.txt, /tmp/test/foo/wibble and then /tmp/test/foo. It will then attempt to process the foo directory which it has just removed, prompting it to produce a warning message. It will then proceed to the next thing in /tmp/test, which is bar. It removes it, and then attempts to enter the bar directory it has just removed and again prints a warning message.

If you add a -depth to the find command then directories are processed after their sub-directories. So the order would be /tmp/test/foo/wibble (which would remove /tmp/test/foo/wibble/hello.txt and /tmp/test/foo/wibble), then /tmp/test/foo (which would remove the now empty /tmp/test/foo directory) and then /tmp/test/bar (which would remove the /tmp/test/bar directory).

2
  • Option -prune (if available) also makes sense with rm -r to not descend at all. Commented Feb 10, 2023 at 0:44
  • @Freddy I totally agree. I thought of mentioning it but didn't because it is not generally applicable. For example if instead of removing directories files were being moved to another location. Commented Feb 10, 2023 at 2:51

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.