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
vazovop
  • 11

2 Answers2

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
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
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...)

xenoid
  • 8,888