1

How do I recursively delete all directories which do not contain any files and make an exclusion of hidden directories?

A lot of the directories that I wish to delete contain hidden directories (dot directories) with files inside them, I do not want these directories.

However, any directories with actually visible files in them - I wish to keep.

Any suggestions?

Example (I wish to delete)

v@localhost:~/test$ ls -al
total 20
drwxrwxr-x   3 v v  4096 Oct 28 04:31 .
drwxr-xr-x 255 v v 12288 Oct 28 04:38 ..
drwxrwxr-x   4 v v  4096 Oct 28 04:31 .hidden

Example (I wish to keep)

v@localhost:~/google.com$ ls -al
total 348
drwxrwxr-x   6 v v   4096 Oct 28 04:39 .
drwxr-xr-x 255 v v  12288 Oct 28 04:38 ..
-rw-rw-r--   1 v v     54 Oct 28 04:39 BCF9360BE20A13B7DA407BF12AF28650.txt
-rw-rw-r--   1 v v    254 Oct 28 04:39 crossdomain.xml
-rw-rw-r--   1 v v   1150 Oct 28 04:39 favicon.ico
-rw-rw-r--   1 v v    234 Oct 28 04:39 .htaccess
-rw-rw-r--   1 v v     23 Oct 28 04:39 index.html
-rw-rw-r--   1 v v    418 Oct 28 04:39 index.php
-rw-rw-r--   1 v v  19935 Oct 28 04:39 license.txt
-rw-rw-r--   1 v v 110249 Oct 28 04:39 php_errors.log
-rw-rw-r--   1 v v   7344 Oct 28 04:39 readme.html
-rw-rw-r--   1 v v   5456 Oct 28 04:39 wp-activate.php
drwxrwxr-x   9 v v   4096 Oct 28 04:39 wp-admin
-rw-rw-r--   1 v v    364 Oct 28 04:39 wp-blog-header.php
-rw-rw-r--   1 v v   1477 Oct 28 04:39 wp-comments-post.php
-rw-rw-r--   1 v v   3376 Oct 28 04:39 wp-config-local.php
-rw-rw-r--   1 v v   5219 Oct 28 04:39 wp-config.php
-rw-rw-r--   1 v v   2853 Oct 28 04:39 wp-config-sample.php
drwxrwxr-x   7 v v   4096 Oct 28 04:39 wp-content
-rw-rw-r--   1 v v   3286 Oct 28 04:39 wp-cron.php
drwxrwxr-x  17 v v  12288 Oct 28 04:39 wp-includes
-rw-rw-r--   1 v v   2382 Oct 28 04:39 wp-links-opml.php
-rw-rw-r--   1 v v   3353 Oct 28 04:39 wp-load.php
-rw-rw-r--   1 v v  34057 Oct 28 04:39 wp-login.php
-rw-rw-r--   1 v v   7993 Oct 28 04:39 wp-mail.php
-rw-rw-r--   1 v v  13920 Oct 28 04:39 wp-settings.php
-rw-rw-r--   1 v v  29890 Oct 28 04:39 wp-signup.php
-rw-rw-r--   1 v v   4035 Oct 28 04:39 wp-trackback.php
-rw-rw-r--   1 v v   3064 Oct 28 04:39 xmlrpc.php
0

rmdir won't remove a non-empty directory so you can do:

find . -type d \! -name '.*' -depth -exec rmdir -v --ignore-fail-on-non-empty {} \;

(where --ignore-fail-on-non-empty is just about error messages...)

0

It gets a little complicated, but you could chain together some find tests, namely:

  • start at the desired directory (/path/to/dir)
  • start from the bottom up (-depth), so that you empty out candidate directories before considering their parent directories
  • consider only directories (-type d)
  • for each of the above matches (one at a time), execute a bash shell that:
    • sets the nullglob shell option ensure that the dotglob shell option is unset
    • uses the $1/* shell glob to set the positional parameters to the number of matching files (and/or directories) in the matched directory -- noting that unsetting dotglob tells bash to not count dot-files (or dot-directories) in the expansion, and that the nullglob option will let the glob expand to nothing if there are no matches at all.
    • if the number of resulting files/directories is zero, return "success"
  • for any directories that passed the above test, execute rm -r on them, as many as will fit in an rm command at a time (+).

Summing up:

find /path/to/dir -depth -type d \
  -exec bash -c \
     'shopt -s nullglob; shopt -u dotglob; set -- $1/*; test "$#" -eq 0' find-sh {} \; \
  -exec rm -r {} +

Hat-tip to Stéphane's find/exec answer here for providing a nice baseline for this answer to start from.

To create a test-bed:

mkdir tmp
cd tmp
mkdir dir{1..3}
touch dir1/.hidden
touch dir2/foo
touch dir3/bar

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.