Copying a file from one directory to another with Ruby - ruby

Hey I'm trying to move multiple files from one folder to another. In the FileUtils line I am trying to search through all of the 4 character folders in the destination folder and then paste the file in the folder with the same base name as the file.
#!/usr/bin/env ruby
require 'fileutils'
my_dir = Dir["C:/Documents and Settings/user/Desktop/originalfiles/*.doc"]
my_dir.each do |filename|
FileUtils.cp(filename, "C:/Documents and Settings/user/Desktop/destinationfolder/****/" + File.basename(filename, ".doc"))
end

Something like this should work.
my_dir = Dir["C:/Documents and Settings/user/Desktop/originalfiles/*.doc"]
my_dir.each do |filename|
name = File.basename('filename', '.doc')[0,4]
dest_folder = "C:/Documents and Settings/user/Desktop/destinationfolder/#{name}/"
FileUtils.cp(filename, dest_folder)
end
You have to actually specify the destination folder, I don't think you can use wildcards.

I had to copy 1 in every 3 files from multiple directories to another. For those who wonder, this is how I did it:
require 'fileutils'
# Print origin folder question
puts 'Please select origin folder'
# Select origin folder
origin_folder = gets.chomp
# Select every file inside origin folder with .png extension
origin_folder = Dir["#{origin_folder}/*png"]
# Print destination folder question
puts 'Please select destination folder'
# Select destination folder
destination_folder = gets.chomp
# Select 1 in every 3 files in origin folder
(0..origin_folder.length).step(3).each do |index|
# Copy files
FileUtils.cp(origin_folder[index], destination_folder)
end

* is a wildcard meaning "any number of characters", so "****" means "any number of any number of any number of any number of characters", which is probably not what you mean.
? is the proper symbol for "any character in this position", so "????" means "a string of four characters only".

Related

Rename specific files depending on a diferent file in same directory

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

Ruby paths with backslash on Mac

Venturing into Ruby lands (learning Ruby). I like it, fun programming language.
Anyhow, I'm trying to build a simple program to delete suffixes from a folder, where user provides the path to the folder in the Mac terminal.
The scenario goes like this:
User runs my program
The program ask user to enter the folder path
User drags and drop the folder into the Mac terminal
Program receives path such as "/Users/zhang/Desktop/test\ folder"
Program goes and renames all files in that folder with suffix such as "image_mdpi.png" to "image.png"
I'm encountering a problem though.
Right now, I'm trying to list the contents of the directory using:
Dir.entries(#directoryPath)
However, it seems Dir.entries doesn't like backslashes '\' in the path. If I use Dir.entries() for a path with backslash, I get an exception saying folder or file doesn't exist.
So my next thought would be to use :
Pathname.new(rawPath)
To let Ruby create a proper path. Unfortunately, even Pathname.new() doesn't like backslash either. My terminal is spitting out
#directoryPath is not dir
This is my source code so far:
# ------------------------------------------------------------------------------
# Renamer.rb
# ------------------------------------------------------------------------------
#
# Program to strip out Android suffixes like _xhdpi, _hpdi, _mdpi and _ldpi
# but only for Mac at the moment.
#
# --------------------------------------------------
# Usage:
# --------------------------------------------------
# 1. User enters a the path to the drawable folder to clean
# 2. program outputs list of files and folder it detects to clean
# 3. program ask user to confirm cleaning
require "Pathname"
#directoryPath = ''
#isCorrectPath = false
# --------------------------------------------------
# Method definitions
# --------------------------------------------------
def ask_for_directory_path
puts "What is the path to the drawable folder you need cleaning?:"
rawPath = gets.chomp.strip
path = Pathname.new("#{rawPath}")
puts "Stored dir path = '#{path}'"
if path.directory?
puts "#directoryPath is dir"
else
puts "#directoryPath is not dir"
end
#directoryPath = path.to_path
end
def confirm_input_correct
print "\n\nIs this correct? [y/N]: "
#isCorrectPath = gets.chomp.strip
end
def reconfirm_input_correct
print "please enter 'y' or 'N': "
#isCorrectPath = gets.strip
end
def output_folder_path
puts "The folder '#{#directoryPath}' contains the following files and folders:"
# Dir.entries doesn't like \
# #directoryPath = #directoryPath.gsub("\\", "")
puts "cleaned path is '#{#directoryPath}'"
begin
puts Dir.entries(#directoryPath)
rescue
puts "\n\nLooks like the path is incorrect:"
puts #directoryPath
end
end
def clean_directory
puts "Cleaning directory now..."
end
puts "Hello, welcome to Renamer commander.\n\n"
ask_for_directory_path
output_folder_path
confirm_input_correct
while #isCorrectPath != 'y' && #isCorrectPath != 'N' do
reconfirm_input_correct
end
if #isCorrectPath == 'y'
clean_directory
else
ask_for_directory_path
end
I went through this learning resource for Ruby two three days ago:
http://rubylearning.com/satishtalim/tutorial.html
I'm also using these resource to figure out what I'm doing wrong:
http://ruby-doc.org/core-2.3.0/Dir.html
https://robm.me.uk/ruby/2014/01/18/pathname.html
Any ideas?
Edit
Well, the current work around(?) is to clean my raw string and delete any backslashes, using new method:
def cleanBackslash(originalString)
return originalString.gsub("\\", "")
end
Then
def ask_for_directory_path
puts "\nWhat is the path to the drawable folder you need cleaning?:"
rawPath = gets.chomp.strip
rawPath = cleanBackslash(rawPath)
...
end
Not the prettiest I guess.
A sample run of the program:
Zhang-computer:$ ruby Renamer.rb
Hello, welcome to Renamer commander.
What is the path to the drawable folder you need cleaning?:
/Users/zhang/Desktop/test\ folder
Stored dir path = '/Users/zhang/Desktop/test folder'
#directoryPath is dir
The folder '/Users/zhang/Desktop/test folder' contains the following files and folders:
cleaned path is '/Users/zhang/Desktop/test folder'
.
..
.DS_Store
file1.txt
file2.txt
file3.txt
Is this correct? [y/N]:
:]
I don't think the problem is with the backslash, but with the whitespace. You don't need to escape it:
Dir.pwd
# => "/home/lbrito/work/snippets/test folder"
Dir.entries(Dir.pwd)
# => ["..", "."]
Try calling Dir.entries without escaping the whitespace.
There is no backslash in the path. The backslash is an escape character displayed by the shell to prevent the space from being interpreted as a separator.
Just like Ruby displays strings containing double quotes by escaping those double quotes.
Okay, first of all, using gets.chomp.strip is probably not a good idea :P
The better and closer solution to what your normally see in a real bash program is to use the Readline library:
i.e.
require "Readline"
...
def ask_for_directory_path
rawPath = String.new
rawPath = Readline.readline("\nWhat is the path to the drawable folder you need cleaning?\n> ", true)
rawPath = rawPath.chomp.strip
rawPath = cleanBackslash(rawPath)
#directoryPath = Pathname.new(rawPath)
end
Using Readline lets you tab complete the folder path. I also needed to clean my backslash from the readline using my own defined:
def cleanBackslash(originalString)
return originalString.gsub("\\", "")
end
After that, the Dir.entries(#directorPath) is able to list all the files and folders in the path, whether the user typed it in manually or drag and drop the folder into the Mac terminal:
Zhang-iMac:Renamer zhang$ ruby Renamer.rb
Hello, welcome to Renamer commander.
What is the path to the drawable folder you need cleaning?
> /Users/zhang/Ruby\ Learning/Renamer/test_folder
The folder '/Users/zhang/Ruby Learning/Renamer/test_folder' contains the following files and folders:
.
..
.DS_Store
drawable
drawable-hdpi
drawable-mdpi
drawable-xhdpi
drawable-xxhdpi
drawable-xxxhdpi
Is this correct? [y/N]: y
Cleaning directory now...
The program is not finish but I think that fixes my problem of the backslash getting in the way.
I don't know how real bash programs are made, but consider this my poor man's bash program lol.
Final program
Check it out:
I feel like a boss now! :D

I need to rename part of the name of multiple files, as per user's indication

Current name of files:
Empty_test-one.txt, Empty_test-two.txt, Empty_test-three.txt
I just want to rename the word Empty. My code so far:
puts "Indicate new name of files":
new_name = gets.chomp
# Look for the specific files
Dir.glob("*.txt").each do |renaming|
# Renaming of files starts, but not on every file
File.rename(renaming, new_name + ".txt")
I'm currently unable to rename each individual file and keep the second part of the file (test-one, test-two, test-three).
Could you please help me?
old_part = "Empty"
puts "Indicate new name of files":
new_name = gets.chomp
# Look for the specific files
Dir.glob("*#{old_part}*.txt").each do |renaming|
full_new_name = renaming.sub(/\A(.*)#{old_part}(.*)\z/, "\\1#{new_name}\\2")
File.rename(renaming, full_new_name)
end
What you were missing was to properly build the new name of file, changing old_name to new_name.

check if directory entries are files or directories using ruby

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 == '..'

Trying to change names of files using Dir and File.rename on Mac OS?

I'm following a tutorial and am trying to change the names of three files in a folder that's located under 'drive/users/myname/test'. I'm getting the error:
'chdir': No such file or directory - test'.
The starting path is already 'drive/users/myname', which is why I thought that I only had to enter 'test' for Dir.chdir.
How do I correctly input the paths on Mac OS?
Dir.chdir('test')
pic_names = Dir['test.{JPG,jpg}']
puts "What do you want to call this batch"
batch_name = gets.chomp
puts
print "Downloading #{pic_names.length} files: "
pic_number = 1
pic_names.each do |p|
print '.'
new_name = "batch_name#{pic_number}.jpg"
File.rename(name, new_name)
pic_number += 1
end
I think you have to provide the absolute path. So, your first line should be:
Dir.chdir("/drive/users/myname/test")
According to the documentation:
Dir.chdir("/var/spool/mail")
puts Dir.pwd
should output/var/spool/mail.
You can look at the documentation for more examples.
In:
File.rename(name, new_name)
name is never defined prior to its attempted use.
Perhaps p is supposed to be name, or name should be p?
With that assumption I'd write the loop something like:
pic_names.each_with_index do |name, pic_number|
print '.'
new_name = "#{ batch_name }#{ 1 + pic_number }.jpg"
File.rename(name, File.join(File.dirname(name), new_name))
end
File.join(File.dirname(name), new_name) is important. You have to refer to the same path in both the original and new filenames, otherwise the file will be moved to a new location, which would be wherever the current-working-directory points to. That's currently masked by your use of chdir at the start, but, without that, you'd wonder where your files went.

Resources