ruby glob for one-level subfolders - ruby

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

Related

ruby - delete all files with names matching a pattern

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.

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

Recursively copy file-types from directory tree

I'm trying to find a way to copy all *.exe files (and more, *.dtd, *.obj, etc.) from a directory structure to another path.
For example I might have:
Code
\classdirA
\bin
\classA.exe
\classdirB
\bin
\classB.exe
\classdirC
\bin
\classC.exe
\classdirD
\bin
\classD.exe
And I want to copy all *.exe files into a single directory, say c:\bins
What would be the best way to do this?
Constraints for my system are:
Windows
Can be Perl, Ruby, or .cmd
Anyone know what I should be looking at here?
Just do in Ruby, using method Dir::glob :
# this will give you all the ".exe" files recursively from the directory "Code".
Dir.glob("c:/Code/**/*.exe")
** - Match all directories recursively. This is used to descend into the directory tree and find all files in sub-directories of the current directory, rather than just files in the current directory. This wildcard is explored in the example code.
* - Match zero or more characters. A glob consisting of only the asterisk and no other characters or wildcards will match all files in the current directory. The asterisk is usually combined with a file extension, if not more characters to narrow down the search.
Nice blog Using Glob with Directories.
Now to copy the files to your required directory, you need to look into the method, FileUtils.cp_r :
require 'fileutils'
FileUtils.cp_r Dir.glob("c:/Code/**/*.exe"), "c:\\bins"
I just have tested, that FileUtils.cp method will also work, in this case :
require 'fileutils'
FileUtils.cp Dir.glob("c:/Code/**/*.exe"), "c:\\bins"
My preference here is to use ::cp method. Because Dir::glob is actually collecting all the files having .exe extensions recursively, and return them as an array. Now cp method is enough here, now just taking each file from the array and coping it to the target file.
Why I am not liking in such a situation, the method ::cp_r ?
Okay, let me explain it here also. As the method name suggests, it will copy all the files recursively from the source to target directory. If there is a need to copy specific files recursively, then ::cp_r wouldn't be able to do this by its own power ( as it can't do selections by itself, which ::glob can do ). Thus in such a situation, you have to give it the specific file lists, it would then copy then to the target directory. If this is the only task, I have to do, then I think we should go with ::cp, rather than ::cp_r.
Hope my explanation helps.
From cmd command line
for /r "c:\code" %f in (*.exe) do copy "%~ff" "c:\bins"
For usage inside a batch file, double the percent signs (%% instead of %)
Windows shell (cmd) command:
for /r code %q in (*.exe) do copy "%q" c:\bin
Double the % characters if you place this in a batch file.

Parsing a directory of files with regex and ruby

I'm trying to do a simple regex to grab specific text out of a bunch of text files in a directory. The code I'm using is below:
input_dir = File.join('path/to/file/dir/', "*.txt")
Dir.glob(input_dir) do |file|
if /\.txt$/i.match file
File.open(file, "r") do |_file|
/==BEGIN==(.*)==END==/.match _file.read
puts $1
end
end
end
That works for exactly 1 of the files in the directory, but all other files return nil. Am I missing something here?
Hard to guess with so little data, but could it be that in most files (except one), ==BEGIN== and ==END== are on different lines?
Does /==BEGIN==(.*)==END==/m.match _file.read change anything? The /m modifier allows the dot to also match newlines in Ruby.

Dir globbing not recursing fully

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'))

Resources