files = Dir[File.join(path, '**', '*.jpg')].each do |s|
puts s
end
I have a bunch of subfolders within a directory and this snippet seems to go into some of the subdirectories, but skips most of them. How can I make it so that it recurses into all directories?
Also, should I be using Find instead? If so, could someone provide an example that does the same as above, namely finding .jpgs in all subdirectories?
EDIT -
Ok, so apparently when I do it with .JPG (capitalized) it finds all the files. Strange... How can I tell to find either of them?
This may help with different extensions:
files = Dir[File.join(path, '**', '*.{jpg,JPG}')].each do |s|
puts s
end
Obviously you forgot use glob method on Dir like:
Dir.glob(File.join('**','*.jpg'))
Related
I'm trying to read every file in a specified directory. I'd like to ignore hidden files. I've found a way to do this, but I'm pretty sure it is the most inefficient way to do this.
This is what I've tried,
Find.find(directory) do |path|
file_paths << path if path =~ /.*\./ and !path.split("/")[-1].to_s.starts_with?(".")
end
This works. But I hate it.
I then tried to do this,
file_paths << path if path =~ /.*\./ and path =~ /^\./
But this returned nothing for me. What am I doing wrong here?
You could just use Dir
file_paths = Dir.glob("#{directory}/*")
Dir#glob Docs:
Returns the filenames found by expanding pattern which is an Array of the patterns or the pattern String, either as an array or as parameters to the block.
Note, this will not match Unix-like hidden files (dotfiles). In order to include those in the match results, you must use something like “{,.}”.
per #arco444 if you want this to search recursively
file_paths = Dir.glob("#{directory}/**/*")
If you wanted to ignore files starting with ., the below would append those that don't to the file_paths array
Find.find(directory) do |path|
if File.file?(path)
file_paths << path unless File.basename(path).start_with?(".")
end
end
Note that this will not necessarily ignore hidden files, for the reasons mentioned in the comments. It also currently includes "hidden" directories, i.e. a file such as /some/.hidden/directory/normal.file would be included in the list.
I want to remove the following characters from several files in a folder. What I have so far is this:
str.delete! '!##$%^&*()
which I think will work to remove the characters. What do I need to do to make it run through all the files in the folder?
You clarified your question, stating you want to remove certain characters from the contents of files in a directory. I created a straight forward way to traverse a directory (and optionally, subdirectories) and remove specified characters from the file contents. I used String#delete like you started with. If you want to remove more advanced patterns you might want to change it to String#gsub with regular expressions.
The example below will traverse a tmp directory (and all subdirectories) relative to the current working directory and remove all occurrences of !, $, and # inside the files found. You can of course also pass the absolute path, e.g., C:/some/dir. Notice I do not filter on files, I assume it's all text files in there. You can of course add a file extension check if you wish.
def replace_in_files(dir, chars, subdirs=true)
Dir[dir + '/*'].each do |file|
if File.directory?(file) # Traverse inner directories if subdirs == true
replace_in_files(file, chars, subdirs) if subdirs
else # Replace file contents
replaced = File.read(file).delete(chars)
File.write(file, replaced)
end
end
end
replace_in_files('tmp', '!$#')
I think this might work, although I'm a little shaky on the Dir class in Ruby.
Dir.foreach('/path/to/dir') do |file|
file.delete '!##$%^&*()
end
There's a more general version of your question here: Iterate through every file in one directory
Hopefully a more thorough answer will be forthcoming but maybe this'll get you where you need.
Dir.foreach('filepath') do |f|
next if Dir.exists?(f)
file = File.new("filepath/#{f}",'r+')
text = file.read.delete("'!##$%^&*()")
file.rewind
file.write(text)
file.close
end
The reason you can't do
file.write(file.read.delete("'!##$%^&*()"))
is that file.read leaves the "cursor" at the end of the text. Instead of writing over the file, you would be appending to the file, which isn't what you want.
You could also add a method to the File class that would move the cursor to the beginning of the file.
class File
def newRead
data = self.read
self.rewind
data
end
end
Dir.foreach('filepath') do |f|
next if Dir.exists?(f)
file = File.new("filepath/#{f}",'r+')
file.write(file.newRead.delete("'!##$%^&*()"))
file.close
end
How can I write glob that will match files only if one-level subfolders? I have a structure like that: src/items/item-name/file.ext
And I need a glob that will match only these files, not src/items/item-name/subfolder/file.ext. I tried to use src/blocks/*/*.*, but it still looks into subfolders.
I'm trying to set up watch action for Compass, and I have to do it with ruby. I'm not familiar with it, and can't find a way to do that myself.
In Ruby, you can catch all the files following the pattern *.* in all subfolders of src/items as following:
Dir.glob('src/items/*/*.*').select({ |f| File.file?(f) }).each do|file|
puts file
end
It doesn't dig deeper (if you don't use ** it doesn't do it recursively ), and it only considers file thanks to File.file? (in case of a subsubfolder name would match the pattern *.*).
How do I get Dir['*'] to include dotfiles, e.g., .gitignore, but not . and ..?
I.e., is there a better way to do:
`ls -A`.split "\n"
perhaps with Dir? The following solutions are close but both include . & ..:
Dir.glob('*', File::FNM_DOTMATCH)
Dir['{.*,*}']
So, the following works:
Dir.glob('*', File::FNM_DOTMATCH) - ['.', '..']
But, is there still a better way to do this?
I'm wondering this to fix line 9 of a Meteor Homebrew Formula.
You can't with Dir[], but you can with Dir.glob, which Dir[] calls:
Dir.glob("*", File::FNM_DOTMATCH)
You can get rid of the . & .. easily:
Dir.glob("*", File::FNM_DOTMATCH).tap { |a| a.shift(2) }
But I think it’s probably best to stick with your original way:
Dir.glob("*", File::FNM_DOTMATCH) - %w[. ..]
(among other ways)
However, if you don’t require a more sophisticated glob than *, Dir#children may be all you need (can always further filter/grep the results if more filtering is needed):
Dir.children('.')
Here's a shorter version:
Dir['{.[^\.]*,*}']
Here is how I did it to find all files in a directory including hidden files and remove .git/, ., .., and directories:
files = Dir.glob("#{ARGV.first}/**/*", File::FNM_DOTMATCH)
files = files.grep_v(/\/.git\//).grep_v(/\/\.$/).grep_v(/\/\.\.$/)
files = files.select { |file| File.file?(file) }
I'm trying to use RubyZip to package up some files. At the moment I have a method which happily zips on particular directory and sub-directories.
def zip_directory(zipfile)
Dir["#{#directory_to_zip}/**/**"].reject{|f| reject_file(f)}.each do |file_path|
file_name = file_path.sub(#directory_to_zip+'/','');
zipfile.add(file_name, file_path)
end
end
However, I want to include a file from a completely different folder. I have a the following method to solve this:
def zip_additional(zipfile)
additional_files.reject{|f| reject_file(f)}.each do |file_path|
file_name = file_path.split('\\').last
zipfile.add(file_name, file_path)
end
end
While the file is added, it also copies the directory structure instead of placing the file at the root of the folder. This is really annoying and makes it more difficult to work with.
How can I get around this?
Thanks
Ben
there is setting to include (or exclude) the full path for zip libraries, check that setting
Turns out it was because the filename had the pull path in. My split didn't work as the path used a / instead of a . With the path removed from the filename it just worked.