I'm trying to store the file names in some directory in an array. I have the following script:
files= Dir.glob('C:\Users\Abder-Rahman\Desktop\drugsatfda\*.*')
files.each do |filename|
contents = IO.read(filename)
puts contents
end
exit
But, I don't know why it doesn't work. What could I be missing?
Unfortunately, it is not described in documentation, but Dir.glob doesn't throw any exception in case you provided invalid path - it will return just empty array.
files = Dir.glob("./an/imaginary/directory/that/doesnt/exist/*")
# => []
Please, make sure, that the path you've provided both - exists, and has any files.
Related
I'm practising some programming and I'm now faced with the following issue. I have a folder with multiple subfolders inside. Each subfolder contains two files: an .xlsx and a .doc file. I want to rename the .xlsx depending on the name of the .doc file. For example, in directory documents\main_folder\folder_1 there are two files: test_file.xlsx and final_file.doc. After running my code, result should be final_file.xlsx and final_file.doc. This must happen with all subfolders.
My code so far:
require 'FileUtils'
filename = nil
files = Dir.glob('**/*.doc')
files.each do |rename|
filename = File.basename(rename, File.extname(rename))
puts "working with file: #{filename}"
end
subs = Dir.glob('**/*.xlsx')
subs.each do |renaming|
File.rename(renaming, filename)
end
Two issues with this code: firstly, the .xlsx is moved where the .rb file is located. Secondly, renaming is partially achieved, only that the extension is not kept, but completely removed. Any help?
Dir.glob('**/*.doc').each do |doc_file|
# extract folder path e.g. "./foo" from "./foo/bar.doc"
dir = File.dirname(doc_file)
# extract filename without extension e.g. "bar" from "./foo/bar.doc"
basename = File.basename(doc_file, File.extname(doc_file))
# find the xlsx file in the same folder
xlsx_file = Dir.glob("#{dir}/*.xlsx")[0]
# perform the replacement
File.rename(xlsx_file, "#{dir}/#{basename}.xlsx")
end
edit
the validation step you requested:
# first, get all the directories
dirs = Dir.glob("**/*").select { |path| File.directory?(path) }
# then validate each of them
dirs.each do |dir|
[".doc", ".xlxs"].each do |ext|
# raise an error unless the extension has exactly 1 file
unless Dir.glob("#{dir}/*#{ext}").count == 1
raise "#{dir} doesn't have exactly 1 #{ext} file"
end
end
end
You can also bunch up the errors into one combined message if you prefer ... just push the error message into an errors array instead of raising them as soon as they come up
I'm writing to a file from a temp file, when I try to read the file that has been written from the temp file, it seems to be adding an extra character to the directory called tmp. (file is passed in through optparse)
Source:
require 'tempfile'
PATH = Dir.pwd
def format_file
puts 'Writing to temporary file..'
if File.exists?(OPTIONS[:file])
file = Tempfile.new('file')
IO.read(OPTIONS[:file]).each_line do |s|
File.open(file, 'a+') { |format| format.puts(s) unless s.chomp.empty? }
end
IO.read(file).each_line do |file|
File.open("#{PATH}/tmp/#sites.txt", 'a+') { |line| line.puts(file) }
end
puts "File: #{OPTIONS[:file]}, has been formatted and saved as #sites.txt in the tmp directory."
else
puts <<-_END_
Woah now my friend! I know you're eager to get those vulns;
But file: #{OPTIONS[:file]} doesn't exist or in this directory at least!
What I'm gonna need you to do is go move that file over here.
It's okay, you're forgiven, I'll wait until you return..
_END_
end
end
Example:
ruby whitewidow.rb -f sites.txt
[12:40:43 INFO]Formatting file
[12:40:43 INFO]Writing to temporary file..
[12:40:43 INFO]File: tmp/sites.txt, has been formatted and saved as #sites.txt in the tmp directory.
[12:40:43 INFO]Let's check out this file real quick like..
whitewidow.rb:224:in `read': No such file or directory # rb_sysopen - C:/Users/Justin/MyScripts/RubySQL/whitewidow/#tmp/#sites.txt (Errno::ENOENT)
#<= Correct path but the '#' in tmp shouldn't be there..
What it does is format the file to remove any empty lines within it (this program doesn't like empty lines) from there it should write to a temp file, rewrite from the temp file back to the original directory (whitewidow/tmp/) and delete the temp file (I know how to do this part).
It seems to me like while rewriting back to the original directory it's adding a # to the directory name (#tmp is actually tmp) is there a reason that it's adding this?
I fixed it, for some reason the program was adding a # to the path, so I gsubed out the # and it works.
Okay. I'm a big noob at Ruby. What did I miss?
I just want to iterate through a particular folder on OS X and if a sub-entry is a directory I want to do something.
My code:
folder = gets.chomp()
Dir.foreach(folder) do |entry|
puts entry unless File.directory?(entry)
# unfortunately directory?
# doesn't work as expected here because everything evaluates to false, but why? How is this supposed to be done?
end
entry contains only basename part (dirname/basename). You need to join it with folder to get correct path.
folder = gets.chomp()
Dir.foreach(folder) do |entry|
path = File.join(folder, entry) # <------
puts entry unless File.directory?(path)
end
In addition to that, you maybe want to skip entry if the entry is . or ...
next if entry == '.' || entry == '..'
Im using
Find.find("c:\\test")
to search for files in a dir. I just want to search the dir at this level though, so any dir within c:\test does not get searched.
Is there another method I can use ?
Thanks
# Temporarily make c:\test your current directory
Dir.chdir('c:/test') do
# Get a list of file names just in this directory as an array of strings
Dir['*'].each do |filename|
# ...
end
end
Alternatively:
# Get a list of paths like "c:/test/foo.txt"
Dir['c:/test/*'] do |absolute|
# Get just the filename, e.g. "foo.txt"
filename = File.basename(absolute)
# ...
end
With both you can get just the filenames into an array, if you like:
files = Dir.chdir('c:/text'){ Dir['*'] }
files = Dir['c:/text/*'].map{ |f| File.basename(f) }
Find's prune method allows you to skip a current file or directory:
Skips the current file or directory,
restarting the loop with the next
entry. If the current file is a
directory, that directory will not be
recursively entered. Meaningful only
within the block associated with
Find::find.
Find.find("c:\\test") do |path|
if FileTest.directory?(path)
Find.prune # Don't look any further into this directory.
else
# path is not a directory, so must be file under c:\\test
# do something with file
end
end
You may use Dir.foreach(), for example, to list all the files under c:\test
Dir.foreach("c:\\test") {|x| puts "#{x}" }
I need to search all the *.c source files in the path to find a reference to a *.h header to find unused C headers. I wrote a ruby script but it feel very clumsy.
I create an array with all C files and an array with all the H files.
I iterate over the header file array. For each header I open each C file and look for a reference to the header.
Is there a easier or better way?
require 'ftools'
require 'find'
# add a file search
class File
def self.find(dir, filename="*.*", subdirs=true)
Dir[ subdirs ? File.join(dir.split(/\\/), "**", filename) : File.join(dir.split(/\\/), filename) ]
end
end
files = File.find(".", "*.c", true)
headers = File.find(".", "*.h", true)
headers.each do |file|
#puts "Searching for #{file}(#{File.basename(file)})"
found = 0
files.each do |cfile|
#puts "searching in #{cfile}"
if File.read(cfile).downcase.include?(File.basename(file).downcase)
found += 1
end
end
puts "#{file} used #{found} times"
end
As already pointed out, you can use Dir#glob to simplify your file-finding. You could also consider switching your loops, which would mean opening each C file once, instead of once per H file.
I'd consider going with something like the following, which ran on the Ruby source in 3 seconds:
# collect the File.basename for all h files in tree
hfile_names = Dir.glob("**/*.h").collect{|hfile| File.basename(hfile) }
h_counts = Hash.new(0) # somewhere to store the counts
Dir.glob("**/*.c").each do |cfile| # enumerate the C files
file_text = File.read(cfile) # downcase here if necessary
hfile_names.each do |hfile|
h_counts[hfile] += 1 if file_text.include?(hfile)
end
end
h_counts.each { |file, found| puts "#{file} used #{found} times" }
EDIT: That won't list H files not referenced in any C files. To be certain to catch those, the hash would have to be explicitly initialised:
h_counts = {}
hfile_names.each { |hfile| h_counts[hfile] = 0 }
To search *.c and *.h files, you could use Dir.glob
irb(main):012:0> Dir.glob("*.[ch]")
=> ["test.c", "test.h"]
To search across any subdirectory, you can pass **/*
irb(main):013:0> Dir.glob("**/*.[ch]")
=> ["src/Python-2.6.2/Demo/embed/demo.c", "src/Python-2.6.2/Demo/embed/importexc.c",
.........
Well, once you've found your .c files, you can do this to them:
1) open the file and store the text in a variable
2) use 'grep' : http://ruby-doc.org/core/classes/Enumerable.html#M003121
FileList in the Rake API is very useful for this. Just be aware of the list size growing larger than you have memory to handle. :)
http://rake.rubyforge.org/