What command sequence can I use to delete directories but not their files?

2

1

How do I delete directories but not the files inside them? I have tried the following:

rm -di /Users/arthur/Desktop/MyFolder 

remove /Users/arthur/Desktop/MyFolder? y
rm: /Users/arthur/Desktop/MyFolder: Directory not empty

I'm on a Mac. BTW, I want to do this automatically.

gadgetmo

Posted 2012-04-03T06:49:54.730

Reputation: 728

Where should the files go? – slhck – 2012-04-03T07:23:48.263

@slhck up a directory – gadgetmo – 2012-04-03T07:30:29.303

Answers

6

Method 1 – First moving, then deleting

Just move the files up one directory and then delete it. This will keep the contained file/folder hierarchy.

mv ~/Desktop/MyFolder/* ~/Desktop/MyFolder/..
rmdir ~/Desktop/MyFolder

Method 2 – Automating in a Shell Function

You can put this into a shell function defined in your ~/.bash_profile:

function rmd () {
  if [ -d "$1" ]; then
    mv "$1"/* "$1"/..
    rmdir "$1"
  else
    echo "$1 is not a directory"
  fi
}

As said before, this will only delete the parent folder, keeping the children hierarchy intact.


Method 3 – Recursive deletion

If you want to recursively remove all folders and just keep files contained, use the following instead:

function rmdr () {
  if [ -d "$1" ]; then
    p="$1"/..
    find "$1" -type f -exec mv '{}' "$p" \;
    rm -rf "$1"
  else
    echo "$1 is not a directory"
  fi
}

Note that this overwrites files with duplicate names.


Method 4 – Recursive deletion with duplicate awareness

Finally, if you want to keep duplicate files, you can check if they already exist. In this case, we'll prepend them with a random number string. Of course, there could be way more sophisticated methods than that, but you can see where this is going.

function rmdr () {
  if [ -d "$1" ]; then
    p="$1"/..
    # loop through all files
    while IFS= read -r -d '' file; do
      filename=$(basename "$file")
      # if it already exists, prefix with random number
      if [ -f "$p/$filename" ]; then
        mv "$file" "$p/$RANDOM-$filename"
      # if it doesn't exist, just move
      else
        mv "$file" "$p"
      fi
    done < <(find "$1" -type f -print0)
    # remove parent directory
    rm -rf "$1"
  else
    echo "$1 is not a directory"
  fi
}

Looping through find output is explained here.

slhck

Posted 2012-04-03T06:49:54.730

Reputation: 182 472

Thanks. Is it possible to do this recursively? – gadgetmo – 2012-04-03T08:35:07.923

You mean, specify one directory, and then eliminate the complete directory hierarchy, just keeping the files? In that case, see my updated answer. – slhck – 2012-04-03T08:41:22.957

Thanks, accepted answer. But what if I have a directory like this: before If I run rmdr /Users/arthur/Desktop/MyFolder, it turns into this: after

– gadgetmo – 2012-04-03T09:55:54.233

That's expected behavior since all files will be moved into the same target directory. In Unix, files with the same name will be overwritten by mv. The question is: What do you expect as output instead? Should duplicate files get another name? – slhck – 2012-04-03T10:08:41.420

They should get another name, if that is possible. Thanks. – gadgetmo – 2012-04-03T10:10:17.350

Added a very simple piece of code to my answer again. – slhck – 2012-04-04T16:06:59.873