Check If Directory Is Empty in Ruby

Check if directory is empty in Ruby

Ruby now has Dir.empty?, making this trivially easy:

Dir.empty?('your_directory') # => (true|false)

In Rubies prior to 2.4.0 you can just get a list of the entries and see for yourself whether or not it's empty (accounting for "." and ".."). See the docs.

(Dir.entries('your_directory') - %w{ . .. }).empty?

# or using glob, which doesn't match hidden files (like . and ..)
Dir['your_directory/*'].empty?

Update: the first method above used to use a regex; now it doesn't (obviously). Comments below mostly apply to the former (regex) version.

Check if path is a directory path (it might not exist)


TL;DR

If the Pathname isn't on the filesystem already, it's just a name. Its type (e.g. file or directory) isn't fixed until you create a filesystem object with it. So, I recommend either unambiguously constructing each directory Pathname with a trailing separator, or using the Pathname to create the file or directory with the relevant methods for its intended type.

Testing Pathname Objects with Trailing Directory Separator

If you're using the Pathname module, the Pathname doesn't have to exist to be used. In such cases, it's useful to note that the Ruby engine converts forward slashes into backslashes when on Windows, so the following constructed pathnames should work on Windows, Linux, MacOS, and Unix:


Pathname('/some/path/').to_s.end_with? ?/
#=> true

Pathname('C:/some/path/').to_s.end_with? ?/
#=> true

However, if your Pathname is constructed manually or programmatically without being read in from the filesystem or using File#join, you may need to use a character class to check for both *nix and Windows trailing separators. For example:

require 'pathname'

%w[ /some/path/ C:\\some\\path\\ ].map do |path|
Pathname(path).to_s.match? %r![/\\]\z!
end
#=> [true, true]

Using Method to Set Filesystem Object Type

If you construct a path without a trailing directory separator but the directory doesn't actually exist in the filesystem, then you can't determine just from the name whether it's supposed to be a file or directory. A Pathname is really just a special type of String object. The documentation explicitly states (emphasis mine):

Pathname represents the name of a file or directory on the filesystem, but not the file itself.

That being the case, your best bet is to modify your Pathname constructor to ensure that you're building names with trailing separators in the first place. If you can't or won't do that, you will have to leave it up to your filesystem writing code to explicitly call an appropriate method explicitly on the expected filesystem object. For example:

require 'pathname'
require 'fileutils'

path = Pathname '/tmp/foo'

# ensure file or directory doesn't already exist
path.rmtree

# use path as file
FileUtils.touch path
path.file?
#=> true

# remove path before next test
path.unlink

# use path as directory
path.mkpath
path.directory?
#=> true

As you can see, a Pathname without a trailing (back)slash can be used for both files and directories, depending on how you use it.

How to check that a Ruby file is empty?

You could use the zero? method:

File.zero?("test.rb")

Ruby: how do I recursively find and remove empty directories?

In ruby:

Dir['**/*']                                            \
.select { |d| File.directory? d } \
.select { |d| (Dir.entries(d) - %w[ . .. ]).empty? } \
.each { |d| Dir.rmdir d }

using ruby to test if a directory is writable?

the command :

File.writable?(directory_path)

does in fact validate if a directory is writable.

so this works for rubys 1.9.3 +

Check if file/folder is in a subdirectory in Ruby

I hope I understood your question correct.

An example:

require 'pathname'

A = '/usr/xxx/a/b/c.txt'
path = Pathname.new(A)

[
'/usr/xxx/a/b',
'/usr/yyy/a/b',
].each{|b|

if path.fnmatch?(File.join(b,'**'))
puts "%s is in %s" % [A,b]
else
puts "%s is not in %s" % [A,b]
end
}

Result:

/usr/xxx/a/b/c.txt is in /usr/xxx/a/b
/usr/xxx/a/b/c.txt is not in /usr/yyy/a/b

The solution uses the class Pathname. An advantage of it: Pathname represents the name of a file or directory on the filesystem, but not the file itself. So you can make your test without a read access to the file.

The test itself is made with Pathname#fnmatch? and a glob-pattern File.join(path,'**') (** means all sub-directories).

If you need it more often, you could extend Pathname:

require 'pathname'
class Pathname
def is_underneath?(path)
return self.fnmatch?(File.join(path,'**'))
end
end

A = '/usr/xxx/a/b/c.txt'
path = Pathname.new(A)

[
'/usr/xxx/a/b',
'/usr/yyy/a/b',
].each{|b|
if path.is_underneath?(b)
puts "%s is in %s" % [A,b]
else
puts "%s is not in %s" % [A,b]
end
}

To handle absolute/relative pathes it may help to expand the pathes like in (sorry, this is untested).

class Pathname
def is_underneath?(path)
return self.expand_path.fnmatch?(File.expand_path(File.join(path,'**')))
end
end

How to check if a given directory exists in Ruby

If it matters whether the file you're looking for is a directory and not just a file, you could use File.directory? or Dir.exist?. This will return true only if the file exists and is a directory.

As an aside, a more idiomatic way to write the method would be to take advantage of the fact that Ruby automatically returns the result of the last expression inside the method. Thus, you could write it like this:

def directory_exists?(directory)
File.directory?(directory)
end

Note that using a method is not necessary in the present case.



Related Topics



Leave a reply



Submit