Can I traverse symlinked directories in Ruby with a ** glob?
Jonathan's clever and cunning approach is great, capable of slashing through hordes of symlinks with but a mere flick of a few asterisks, muahaha. However, it has the unfortunate side-effect of not returning immediate-child matches. An improved version might be:
Dir.glob("**{,/*/**}/*.rb")
Which will (in my tests) do both follow one symlink and return immediate children.
ZSH how to glob non-symlink files inside symlink directories
To follow symbolic links, you need yet another asterisk:
***/*.log
Look for the Recursive Globbing section in the zshexpn
man page.
Depending on how your links are set up, you could get the same file listed multiple times in the glob results (that's probably why zsh doesn't include symbolic links in the ** pattern).
Confusion about Dir[] and File.join() in Ruby
File.join() simply concats all its arguments with separate slash.
For instance,
File.join("a", "b", "c")
returns "a/b/c". It is alsmost equivalent to more frequently used Array's join method, just like this:
["hello", "ruby", "world"].join(", ")
# => "hello, ruby, world"
Using File.join(), however, additionaly does two things: it clarifies that you are getting something related to file paths, and adds '/' as argument (instead of ", " in my Array example). Since Ruby is all about aliases that better describe your intentions, this method better suits the task.
Dir[] method accepts string or array of such strings as a simple search pattern, with "*" as all files or directories, and "**" as directories within other directories. For instance,
Dir["/var/*"]
# => ["/var/lock", "/var/backups", "/var/lib", "/var/tmp", "/var/opt", "/var/local", "/var/run", "/var/spool", "/var/log", "/var/cache", "/var/mail"]
and
Dir["/var/**/*"]
# => ["/var/lock", "/var/backups", "/var/backups/dpkg.status.3.gz", "/var/backups/passwd.bak" ... (all files in all dirs in '/var')]
It is a common and very convinient way to list or traverse directories recursively
Difference between pattern syntax in RSpec::Core::RakeTask and Pathname/Dir.glob
How glob patterns are used in RSpec::Core::RakeTask
RSpec::Core::RakeTask
just runs the rspec
executable. Setting a task's pattern just passes the pattern with the --pattern
flag.
RSpec first constructs a list of paths in which to look for specs. If no files or directories are given on the command line, a single default path is used, 'spec'. RSpec looks for the pattern in each path. If the pattern begins with the path, RSpec just globs the pattern. If the pattern doesn't begin with the path, RSpec prepends the path to the pattern. So:
- The pattern
**/spec/**/*_spec.rb
begins with a wildcard, so RSpec prepends the path, andspec/**/spec/**/*_spec.rb
doesn't match anything. - The pattern
spec/**/*_spec.rb
begins with the path, so RSpec just uses it and it works.
The pattern **/*_spec.rb
would also work; RSpec would prepend spec/
.
RSpec::Core::RakeTask
's default pattern
This part of the pattern **{,/*/**}
allows it to follow symlinks. I don't know why RSpec::Core::RakeTask
follows symlinks by default and command-line rspec
doesn't.
I believe the the rake task's default pattern only works because RSpec recognizes that it begins with the path and doesn't prepend the path. I think if it were **{,/*/**}/*_spec.rb
it would be clearer and would work in more situations.
Check if there is any file or directory matching pattern using ruby
Ruby-only
You could use Find
, find
and find
:D.
I couldn't find any other File/Dir method that returns an Enumerator.
require 'find'
Find.find("/var/data/").find{|f| f=~/\.xml$/i }
#=> first xml file found inside "/var/data". nil otherwise
# or
Find.find("/var/data/").find{|f| File.extname(f).downcase == ".xml" }
If you really just want a boolean :
require 'find'
Find.find("/var/data/").any?{|f| f=~/\.xml$/i }
Note that if "/var/data/"
exists but there is no .xml
file inside it, this method will be at least as slow as Dir.glob
.
As far as I can tell :
Dir.glob("/var/data/**/*.xml"){|f| break f}
creates a complete array first before returning its first element.
Bash-only
For a bash-only solution, you could use :
compgen
- Shell
find
Related Topics
Why Doesn't Ruby Have a Real Stringbuffer or Stringio
What Exactly "Config.Assets.Debug" Setting Does
How to Create a Hash in Ruby That Compares Strings, Ignoring Case
Problem with Quantifiers and Look-Behind
Where Should My Non-Model/Non-Controller Code Live
What Does &: Mean in Ruby, Is It a Block Mixed with a Symbol
What Exactly Is Arel in Rails 3.0
Insecure World Writable Dir /Users/Username in Path, Mode 040777 When Running Ruby Commands
Dynamic Method Calling in Ruby
Ruby Timeouts and System Commands
Rails Date Format in Form Field
Why Is Gets Throwing an Error When Arguments Are Passed to My Ruby Script
How to Identify Aliased Methods in Ruby
How Is a Local Variable Created Even When If Condition Evaluates to False in Ruby
Exponentiation in Ruby 1.8.7 Returns Wrong Answers
Rspec: "Array.Should == Another_Array" But Without Concern for Order