Pages

Thursday, 21 January 2021

find and remove folders: No such file or directory

1 Example

$ tree .
.
├── dir1
├── dir2
├── dir3
├── dir4
└── dir5
$ find . -name dir1 -exec rm -rf {} \;
find: ‘./dir1’: No such file or directory
$ ls
dir2  dir3  dir4  dir5

The directory "./dir1" was removed, however, a warning message was printed.

2 Explanation

Below is the action steps find did:
  1. searched the folder ./dir1
  2. "rm -rf ./dir1"
  3. tried to enter "./dir1/" to find other folders named "dir1"
  4. ...
Here is the problem, even though "./dir1" was removed, find was NOT aware of this and still tried to enter the non-existing-anymore folder.

The reason for such a behavior is that find cannot identify "rm -rf" as a command to delete a folder. Actually, this is reasonable. The users may remove a folder with different command/script names; it's impossible for find to know all about it.

3 Solutions

3.1 Ignore it

Even find printed the error message, folder "./dir1" was removed as expected. So it's safe to ignore the messages.

$ find . -name dir1 -exec rm -rf {} \; 2>/dev/null

But this is not perfect as it also put other useful error messages into /dev/null. For example, "rm -rf ./dir1" may fail due to insufficient permissions, but you cannot see the errors with this command line.

3.3 use "-depth"

The '-depth' option indicates "deep first" algorithm, which changes the workflow as below:
  1. searched the folder ./dir1
  2. Enter "./dir1/" to find other folders named "dir1" and remove it
  3. "rm -rf ./dir1"
  4. ...
$ find . -depth -name dir1 -exec rmdir {} \;

To illustrate more, we created another folder "./dir1/dir1" and checked the workflow.

$ find .  -name dir1 -exec ls -d {} \;
./dir1
./dir1/dir1
$ find . -depth -name dir1 -exec ls -d {} \;
./dir1/dir1
./dir1

It's clear that with '-depth', subfolders are handled before their containing folders.

3.2 use "-delete"

Fortunately, find has a built-in function to remove files/folders.

$ find . -name dir1 -delete

"-delete" actually implicitly applies "-depth".

What's better is that '-delete' works just like "rm -rf", so it can remove both folders and files.

3.4 use "-maxdepth 1" (preferred)

With "-maxdepth 1", find will NOT enter subfolders at all.

find . -maxdepth 1 -name dir1 -exec rm -rf {} \;

$ find . -maxdepth 1 -name dir1 -exec ls -d {} \;
./dir1

This would decrease the items that find to search, so the performance would be improved if many subfolders exist.

No comments:

Post a Comment