Delete all empty folders, even with .svn folders in it

6

I'm trying to delete all empty folders within a directory. However, find . -type f -empty does not find anything because every folder contains a hidden .svn folder.

How can I work around this?

atamanroman

Posted 2011-02-25T12:58:49.893

Reputation: 263

Are the .svn directories empty? – Paused until further notice. – 2011-02-25T15:31:16.603

No, they are not. I think Ollis solution will work. However, I did not test it yet. – atamanroman – 2011-02-25T15:53:57.600

Answers

1

If you can, you can off course first remove all .svn folders. Downside: you'll lose version control information, if someone is using SVN. If someone is using SVN, then it's not good idea to just remove those folders (or actually you have to remove those from SVN too, as SVN is tracking folders and files).

If that's not possible, I would go with scripting route:

for folder in $(find . -type d); do
 if [ "`ls $folder | wc -l`" -eq 0 ]; then
  echo "I am going to delete $folder"
 fi
done

First try test-run, because there might be something surprising. Then you can change rm -r instead of that echo.

Note however, this will remove all folders with only dot-files (so for example a/.this_is_super_important will be deleted, if there is no other files or folders).

Olli

Posted 2011-02-25T12:58:49.893

Reputation: 6 704

3

Minor modification (simply print the directory and pipe into xargs later):

for folder in $(find -type d ! -path *.svn*); do
  if [ "`find $folder ! -path *.svn* ! -path $folder | wc -l`" -eq 0 ]; then
    echo $folder
  fi
done

Put this somewhere in your $PATH, maybe as svn-empties and then first run:

svn-empties

to list which directories it found (modify list if necessary) and then pipe into xargs:

svn-empties | xargs svn rm

This script has become very useful to me while using git-svn (thank you!). Since git does not track empty directories I can end up with many empty directories in the Subversion repository. I svn co a separate copy of the repository and run svn-empties | xargs svn rm periodically. Using Subversion in the first place was not my decision ;)

ndawe

Posted 2011-02-25T12:58:49.893

Reputation: 31

If you are using git-svn you may want to use the --rmdir option of git svn dcommit. It will take care of removing directories from svn as soon as they are empty. – gioele – 2015-09-11T08:36:19.257

2

I just stumbled upon this and I used this script but modified it to properly consider empty dirs only the ones with .svn and no other file, hidden or normal.

Also, bear in mind that I am using svn rm, so this is suppose to work against a repository, you could adapt the script to do something different on the directory.

for folder in $(find -type d ! -path *.svn*); do
  if [ "`find $folder ! -path *.svn* ! -path $folder | wc -l`" -eq 0 ]; then
    svn rm $folder
  fi
done

Mescalito

Posted 2011-02-25T12:58:49.893

Reputation: 121

0

  1. resolved the problem that : spaces in Path
  2. can call the script with PATH parameter like this:

svn-empties YOU_WANT_TO_SEARCH_PATH

C_IFS=$IFS

IFS=$'\n'

for folder in $(find "$1" -depth -type d ! -path *.svn*|sort -r); do
  counts=$(find "$folder" -type f ! -path *.svn* ! -path $folder | wc -l)

  if [ $counts -eq 0 ]; then
    echo $folder
  fi

done

IFS=$C_IFS

rhinoceros.xn

Posted 2011-02-25T12:58:49.893

Reputation: 101

0

To avoid problems with white space, find and IFS magic (filenames can actually contain newlines as well, so IFS=$'\n' is not a silver bullet), one could use globs and arrays.

#!/bin/bash
search_dir=${1:-.}
shopt -s globstar dotglob
for svn_dir in "$search_dir"/**/.svn/; do
    base_dir=${svn_dir%/.svn/}
    base_dir_contents=("$base_dir"/*)
    if [ ${#base_dir_contents[@]} -eq 1 ]; then
        printf 'The directory "%s" only contains ".svn/".\n' "$base_dir"
    fi
done
  • The script takes an optional path argument, or uses the current path as default if missing.
  • globstar enables the directory traversing ** construct.
  • dotglob includes hidden files in asterisk globs.
  • The for glob should be safe against any problematic directory name characters. Globs will always expand safely in Bash, which is not the case with ls, find, etc. The trailing slash makes sure we only match folders named .svn and not regular files (a real corner case, though).
  • The names of the files contained in the folder with the matched .svn directory are globbed into an array. If the number of items in this array is 1 (i.e. the .svn folder that we by construction know* is there), then it is what we are looking for.

It only uses Bash built-ins and thus should be faster than issuing extra system forks for find, but the difference is most likely not noticeable, and I/O will be the main bottleneck anyway.


*: Minor sidenote (applies to the other solutions as well): there is a potential race condition if there is e.g. only the .svn and the foo file in a directory, and the .svn directory is removed between the for and the array glob which would result in foo being removed as well. However, if someone with malicious intent has the privilege to remove files in the file system, the game is probably already lost, and they could easier be removed directly than through timing attacks.


Another quick mention is that the other answers should quote their *.svn* expansions. Otherwise the find command will fail if the current folder contains a file that matches that glob:

$ mkdir foo && cd foo
$ mkdir -p test1/.svn test2
$ find -type d ! -path *.svn*
.
./test1
./test2
$ touch foo.svnbar
$ find -type d ! -path *.svn*
.
./test1
./test1/.svn
./test2
$ find -type d ! -path "*.svn*"
.
./test1
./test2

Without quotes, *.svn* will be prematurely expanded by the shell to foo.svnbar.

Daniel Andersson

Posted 2011-02-25T12:58:49.893

Reputation: 20 465