68

I'm trying to delete a non-empty directory in Ruby and no matter which way I go about it it refuses to work. I have tried using FileUtils, system calls, recursively going into the given directory and deleting everything, but always seem to end up with (temporary?) files such as

.__afsECFC
.__afs73B9

Anyone know why this is happening and how I can go around it?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Ced
  • 1,117
  • 1
  • 8
  • 16
  • Can you show us how you what method you are calling and how you are calling it? The reason why I ask is because @ismaelga 's answer works fine for me too. – Martin Velez Sep 09 '12 at 06:02
  • I had tried using `FileUtils.rm_rf('directorypath/name')` as @ismealga suggested, as well as ``rm -rf @{path}`` but as I was not correctly closing my files, they were creating those temporary ones – Ced Sep 10 '12 at 03:06

5 Answers5

119
require 'fileutils'

FileUtils.rm_rf('directorypath/name')

Doesn't this work?

Ismael Abreu
  • 16,443
  • 6
  • 61
  • 75
  • 1
    No, it creates those files, and doesn't delete the directory – Ced Sep 09 '12 at 01:10
  • can it be because you don't have permissions to delete them? – Ismael Abreu Sep 09 '12 at 01:23
  • I'm pretty sure I have permission to change them, as they are being created in the same program, and I can delete individual files without issue – Ced Sep 09 '12 at 01:36
  • 1
    from [the docs](https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html#method-c-rm_r) > WARNING: This method causes local vulnerability if one of parent directories or removing directory tree are world writable (including /tmp, whose permission is 1777), and the current process has strong privilege such as Unix super user (root), and the system has symbolic link. For secure removing, read the documentation of ::remove_entry_secure carefully, and set :secure option to true. Default is secure: false. – Kostis Jun 25 '20 at 20:44
67

Safe method: FileUtils.remove_dir(somedir)

esilver
  • 27,713
  • 23
  • 122
  • 168
merqlove
  • 3,674
  • 1
  • 23
  • 22
  • 11
    What makes it 'safe'? – Tallboy Apr 23 '18 at 16:54
  • @Tallboy Removes a directory somedir and its contents recursively. This method ignores StandardError if force is true. FYI – merqlove Apr 24 '18 at 17:50
  • does it prevent accidental catostrophic things like removing `/`? – Tallboy Apr 24 '18 at 23:13
  • 1
    @Tallboyyou try to check it yourself, i haven't tried this condition. But i proud that in this case you will have Permissions error. Run Ruby apps within non-root user! – merqlove May 07 '18 at 02:17
  • 1
    I'd hardly call a method that recursively deletes a directory and all of its contents "safe". If anything this is the unsafe variant, as any other method would produce a warning if you try to remove a directory without handling its contents first. – Sollace Aug 20 '20 at 11:07
14

Realised my error, some of the files hadn't been closed. I earlier in my program I was using

File.open(filename).read

which I swapped for a

f = File.open(filename, "r")
while line = f.gets
    puts line
end
f.close

And now

FileUtils.rm_rf(dirname)

works flawlessly

Ced
  • 1,117
  • 1
  • 8
  • 16
  • 8
    If you're just reading the full file, you can do `File.read filename` (at least in MRI, I don't think JRuby or Rubinius support this yet), and if you want to do it the way you're showing, it's better to use the block form, because it ensures the file gets closed: `File.open(filename, "r") { |file| ... }` or `File.foreach(filename) { |line| ... }` – Joshua Cheek Sep 09 '12 at 04:58
6

I guess the best way to remove a directory with all your content "without using an aditional lib" is using a simple recursive method:

def remove_dir(path)
  if File.directory?(path)
    Dir.foreach(path) do |file|
      if ((file.to_s != ".") and (file.to_s != ".."))
        remove_dir("#{path}/#{file}")
      end
    end
    Dir.delete(path)
  else
    File.delete(path)
  end
end
remove_dir(path)
JonatasTeixeira
  • 1,474
  • 1
  • 18
  • 24
1

The built-in pathname gem really improves the ergonomics of working with paths, and it has an #rmtree method that can achieve exactly this:

require "pathname"

path = Pathname.new("~/path/to/folder").expand_path
path.rmtree
Alexander
  • 59,041
  • 12
  • 98
  • 151