I am having problems splitting the filepath and just getting the filenames.
Here is my Code:
file=File.new("files.txt", "w")
file_list=Dir["../path/*txt"]
file.puts file_list
I tried a few different ways to split it, but I keep getting an Array Error,
Best Regards,
AZCards
Please try this snippet:
file = File.new("files.txt", "w")
Dir['../path/*.txt'].each { |f| file.puts File.basename(f, '.txt') }
That give you a list of filenames in specified folder without 'txt' extension.
file=File.new("files.txt", "w")
Dir.entries("/path/to/directory").each do |path|
m = /([^\/]+)\.txt$/.match(path)
file.puts m[1] if m
end
Just map the list of full paths, using basename, yielding the bare filename list.
Assuming you can want to drop extensions:
file = File.new("files.txt", "w")
file_list = Dir["../path/*txt"].map {|f| File.basename f, '.txt'}
file.puts file_list
Related
I got a ruby script which take XML files and create from them CSV. This CSV use semicolons as delimiter -> but, content of XML contains these tags:
- &
- <
- >
And this of course break the structure of CSV file. I need clean it up. This cleaner must be writen in Ruby. I try next code, but this complete destroy the file.
#Clean up CSV file
#Remove: & \< >
file_names = ['terms.csv']
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/&/, " and ")
# To merely print the contents of the file, use:
puts new_contents
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts new_contents }
end
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/</, " < ")
puts new_contents
File.open(file_name, "w") {|file| file.puts new_contents }
end
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/>/, " > ")
puts new_contents
File.open(file_name, "w") {|file| file.puts new_contents }
end
I never use Ruby - this is my first contact. Is there better way how to do this?
I solved it... I change CSV delimiter from ";" to "#" in FOR cycle which create a CSV file. It is not ideal solution, but it works.
I have a directory structure with sub-directories:
../../../../../MY_PROJECT/TEST_A/cats/
../../../../../MY_PROJECT/TEST_B/dogs/
../../../../../MY_PROJECT/TEST_A/tigers/
../../../../../MY_PROJECT/TEST_A/elephants/
each of which has a file that ends with ".sln":
../../../../../MY_PROJECT/TEST_A/cats/cats.sln
../../../../../MY_PROJECT/TEST_B/dogs/dogs.sln
...
These files contain information specific to their directory. I would like to do the following:
Create a file "myfile.txt" within each sub-directory, and write some strings to them:
../../../../../MY_PROJECT/TEST_A/cats/myfile.txt
../../../../../MY_PROJECT/TEST_B/dogs/myfile.txt
../../../../../MY_PROJECT/TEST_A/tigers/myfile.txt
../../../../../MY_PROJECT/TEST_A/elephants/myfile.txt
Copy a specific string in the ".sln" files to the myfile.txt of certain directories using the following method:
def parse_sln_files
sln_files = Dir["../../../../../MY_PROJECT/TEST_*/**/*.sln"]
sln_files.each do |file_name|
File.open(file_name) do |f|
f.each_line { |line|
if line =~ /C Source files ="..\\/ #"
path = line.scan(/".*.c"/)
puts path
end
}
end
end
end
I would like to do something like this:
def create_myfile
Dir['../../../../../MY_PROJECT/TEST_*/*/'].each do |dir|
File.new File.join(dir, 'myfile.txt'), 'w+'
Dir['../../../../../TEST/TEST_*/*/myfile.txt'].each do |path|
File.open(path,'w+') do |f|
f.puts "some text...."
f.puts "some text..."
f.puts # here I would like to return the result of parse_sln_files
end
end
end
end
Any suggestions on how to express this?
It seems like you want to read list of C file names from a Visual C++ Solution file, and store in a separate file in the same directory. You may have to merge the two loops that you have shown in your code, and do something like this:
def parse_sln_and_store_source_files
sln_files = Dir["../../../../../MY_PROJECT/TEST_*/**/*.sln"]
sln_files.each do |file_name|
#### Lets collect source file names in this array
source_file_names = []
File.open(file_name) do |f|
f.each_line { |line|
if line =~ /C Source files ="..\\/ #"
path = line.scan(/".*.c"/)
############ Add path to array ############
source_file_names << path
end
}
end
#### lets create `myfile.txt` in same dir as that of .sln
test_file = File.expand_path(File.dirname(file_name)) + "/myfile.txt"
File.open(test_file,'w+') do |f|
f.puts "some text...."
f.puts "some text..."
##### Iterate over source file names & write to file
source_file_names.each { |n| f.puts n }
end
end
end
This can be done bit more elegantly with few more refactoring. Also note that this is not tested code, hopefully, you get the gist of what I am suggesting.
I am trying to recursively replace a whole line from index.html files into a directory with sub-directories.
The code above puts the right lines I'm searching with the var "pattern", but when I run it, it removes everything form my index.html files.
pattern = "Keyword"
replacement = "<td width=\"30\"><img src=\"styles/img/trans.gif\" width=\"30\"></td>"
Dir.glob('/Users/root/Desktop/directory/test/**/index.html') do |item|
next unless File.file?(item)
File.open(item, "w+:ASCII-8BIT") do |f|
f.each_line do |line|
if line.match(pattern)
my_line = line
line.sub(my_line, replacement)
end
end
end
end
What am I doing wrong ?
You need to read the file first, build the expected output, and then write it:
Dir.glob('/Users/root/Desktop/directory/test/**/index.html') do |item|
next unless File.file?(item)
output = IO.readlines(item).map do |line|
if line.match(pattern)
replacement
else
line
end
end
File.open(item, "w+:ASCII-8BIT") do |f|
f.write output.join
end
end
end
You use File.open with open mode w+ which, according to Ruby documentation, is:
"w+" Read-write, truncates existing file to zero length or creates a new file for reading and writing.
To read the file and put some lines use r:
File.open(item, "r:ASCII-8BIT")
I am trying to write a script to do the following:
There are two directories A and B. In directory A, there are files called "today" and "today1". In directory B, there are three files called "today", "today1" and "otherfile".
I want to loop over the files in directory A and append the files that have similar names in directory B to the files in Directory A.
I wrote the method below to handle this but I am not sure if this is on track or if there is a more straightforward way to handle such a case?
Please note I am running the script from directory B.
def append_data_to_daily_files
directory = "B"
Dir.entries('B').each do |file|
fileName = file
next if file == '.' or file == '..'
File.open(File.join(directory, file), 'a') {|file|
Dir.entries('.').each do |item|
next if !(item.match(/fileName/))
File.open(item, "r")
file<<item
item.close
end
#file.puts "hello"
file.close
}
end
end
In my opinion, your append_data_to_daily_files() method is trying to do too many things -- which makes it difficult to reason about. Break down the logic into very small steps, and write a simple method for each step. Here's a start along that path.
require 'set'
def dir_entries(dir)
Dir.chdir(dir) {
return Dir.glob('*').to_set
}
end
def append_file_content(target, source)
File.open(target, 'a') { |fh|
fh.write(IO.read(source))
}
end
def append_common_files(target_dir, source_dir)
ts = dir_entries(target_dir)
ss = dir_entries(source_dir)
common_files = ts.intersection(ss)
common_files.each do |file_name|
t = File.join(target_dir, file_name)
s = File.join(source_dir, file_name)
append_file_content(t, s)
end
end
# Run script like this:
# ruby my_script.rb A B
append_common_files(*ARGV)
By using a Set, you can easily figure out the common files. By using glob you can avoid the hassle of filtering out the dot-directories. By designing the code to take its directory names from the command line (rather than hard-coding the names in the script), you end up with a potentially re-usable tool.
My solution....
def append_old_logs_to_daily_files
directory = "B"
#For each file in the folder "B"
Dir.entries('B').each do |file|
fileName = file
#skip dot directories
next if file == '.' or file == '..'
#Open each file
File.open(File.join(directory, file), 'a') {|file|
#Get each log file from the current directory in turn
Dir.entries('.').each do |item|
next if item == '.' or item == '..'
#that matches the day we are looking for
next if !(item.match(fileName))
#Read the log file
logFilesToBeCopied = File.open(item, "r")
contents = logFilesToBeCopied.read
file<<contents
end
file.close
}
end
end
Below is the piece of code that is supposed read the directory and for each file entry prints the first row of the file. The issue is x is not visible so file is not being parsed.
Dir.foreach("C:/fileload/src") do |file_name|
x = file_name
puts x
f = File.open("C:/fileload/src/" +x)
f.readlines[1..1].each do |line|
puts line
end
end
Why are you assigning x to file_name? You can use file_name directly. And if you are only reading the first line of the file, why not try this?
#!/usr/bin/ruby
dir = "C:/fileload/src"
Dir.foreach(dir) do |file_name|
full = File.join(dir, file_name)
if File.file?(full)
f = File.open(full)
puts f.first
f.close
end
end
You should use File.join to safely combine paths in Ruby. I also checked that you are opening a file using the File.file? method.
You have no visibility issue with x. You should be using File::join or Pathname#+ to build your file paths. You should exclude non-files from consideration. You're selecting the second line, not the first with [1..1]. Here's a cleaner correct replacement for your sample code.
dir = "C:/fileload/src"
Dir.foreach(dir).
map { |fn| File.join(dir,fn) }.
select { |fn| File.file?(fn) }.
each { |fn| puts File.readlines(fn).first }