ruby - delete all files with names matching a pattern - ruby

I have multiple files (in a folder containing thousands of files), ex:
...
page_bonus.txt
page_code1.txt
page_code2.txt
page_text1.txt
page_text2.txt
page_text3.txt
...
How do I delete all page_code* files?
Note: I do not wish to use FileUtils or shell

Dir::glob supports a single character wildcard (i.e. ?). Based on your example, you could locate the appropriate files in a given directory using ? and then delete them.
Dir.glob('/home/your_username/Documents/page_code?.txt').each { |file| File.delete(file)}

To delete files with a wildcard.
Dir.glob("/tmp/files/*").select{ |file| /MY STRING/.match file }.each { |file| File.delete(file)}
The regular expression within the select is used to grab the files you want.

Related

Why are Ruby's file related types string-based (stringly typed)?

e.g. Dir.entries returns an array of strings vs an array containing File or Dir instances.
Most methods on Dir and File types. The instances are aneamic in comparison.
There is no Dir#folders or Dir#files - instead I explicitly
loop over Dir.entries
build the path (File.expand_path) for
each item
check File.directory?
Simple use-cases like get all .svg files in this directory seem to require a number of hoops/loops/checks. Am I using Ruby wrong or does this facet of Ruby seem very un-ruby-ish?
Depending on your needs, File or Dir might do just fine.
When you need to chain commands and (rightfully) think it feels un-ruby-ish to only use class methods with string parameters, you can use Pathname. It is a standard library.
Examples
Dirs and Files
require 'pathname'
my_folder = Pathname.new('./')
dirs, files = my_folder.children.partition(&:directory?)
# dirs is now an Array of Pathnames pointing to subdirectories of my_folder
# files is now an Array of Pathnames pointing to files inside my_folder
All .svg files
If for some reason there might be folders with .svg extension, you can just filter the pathnames returned by Pathname.glob :
svg_files = Pathname.glob("folder/", "*.svg").select(&:file?)
If you want a specific syntax :
class Pathname
def files
children.select(&:file?)
end
end
aDir = Pathname.new('folder/')
p aDir.files.find_all{ |f| f.extname == '.svg' }
Iterating the Directory tree
Pathname#find will help.
Until you open the file it is just a path (string).
To open all .svg files
svgs = Dir.glob(File.join('/path/to/dir', '*.svg'))
On windows case doesn't matter in file paths, but in all unixoid systems (Linux, MacOS...) file.svg is different from file.SVG
To get all .svg files and.SVG files you need File::FNM_CASEFOLD flag.
If you want to get .svg files recursively, you need **/*.svg
svgs = Dir.glob('/path/to/dir/**/*.svg', File::FNM_CASEFOLD)
If you expect directories ending in.svg then filter them out
svgs.reject! { |path| File.directory?(path) }

Pathname with Regex

I would like to know how to use Regex when instantiating a new Pathname.
I am instantiating a Pathname and passing it to FileUtils#rm_rf to delete the file. The problem I am trying to solve is to remove files that have a certain name without regard to extension:
See this contrived example:
target = Pathname.new(["#{#app_name}/#{#file_name}"])
FileUtils.rm_rf(target)
#file_name does not include extensions such as .rb or html.erb, but I would like to match all files with name equal to #file_name no matter what extensions they use.
My initial approach was to use Regex. But how can I use it, or any other suggestions?
You can use Dir.Glob like this:
Dir.glob("#{#app_name}/#{#file_name}.*").each { |f| File.delete(f) }
See more on that at http://ruby-doc.org/core-2.2.1/Dir.html#method-c-glob

Remove certain characters from several files

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

ruby glob for one-level subfolders

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 *.*).

Recursively find folder names only (not files)

Is it possible to display the folder names (only) recursively. I know, to display the files from the specific folder using the following command.
Dir.glob("/home/test/**/*.pdf")
or
Dir['/home/test/**/*.*']
But, i need to display folder name only.
you put a slash, like this
Dir["**/"].each {|x| puts x}

Resources