问题
I have a file hierarchy and some of the sub-directories are relative symlinks. I am using Ruby's Find.find to crawl through these dirs and find some specific files. However it's not looking into any directory which is a symlink (it follows files which are symlinks).
Looking at the source code it seems the problem is because it's using File.lstat(file).directory?
to test if something is a directory. This returns false
for symlinks but File.stat.directory?
returns true
.
How can I make Find.find
follow symlinks, short of monkey patching it to use File.stat
instead of File.lstat
?
回答1:
I came across the similar situation and decided to follow the real path without extra gem.
require 'find'
paths = ARGV
search_dirs = paths.dup
found_files = Array.new
until search_dirs.size == 0
Find.find( search_dirs.shift ) do |path|
if File.directory?( path ) && File.symlink?( path )
search_dirs << File.realdirpath( path )
else
found_files << path
end
end
end
puts found_files.join("\n")
This way can't keep the original path with symbolic link but is fine for me at the moment.
回答2:
Use the file-find library by Daniel J. Berger. It's available as a Ruby gem. Then you can find recursively with:
require 'rubygems'
require 'file/find'
File::Find.new(:follow => false).find { |p| puts p }
NB: contrary to the documentation and intuition, setting :follow => false will actually make File::Find follow all symlinks, at least on my machine (Ubuntu 10.04, Ruby 1.8.7, file-find 0.3.4).
There is a bunch of other options available for File::Find, like name pattern, file type, atime, ctime, mtime, etc. Take a look at the RDoc.
回答3:
why not use Dir
instead ? It follows symlinks
Or you can try alib
To make Dir
find files recursively, try double asterix Dir["**/*"]
回答4:
Wrote another option with loop checking and only limited recursion. Works with jruby as well.
Here's a gist: https://gist.github.com/akostadinov/05c2a976dc16ffee9cac
回答5:
For anyone else watching, I ended up using Pathname and the following recursive code:
def all_files_under(*paths)
paths.flatten!
paths.map! { |p| Pathname.new(p) }
files = paths.select { |p| p.file? }
(paths - files).each do |dir|
files << all_files_under(dir.children)
end
files.flatten
end
回答6:
Here is a simpler and more efficient version of the recursive Pathname method:
def find_files(*paths)
paths.flatten.map do |path|
path = Pathname.new(path)
path.file? ? [path.to_s] : find_files(path.children)
end.flatten
end
来源:https://stackoverflow.com/questions/3974087/how-to-make-rubys-find-find-follow-symlinks