Rename method of Ruby; escaping colon - ruby

How do you escape a colon, when renaming files in Ruby?
I have following code (names is a hash with data already filled in):
new_filename = ""
counter = 0
Dir.glob(folder_path + "/*").each do |f|
numbering = names.index(names.values.sort[counter])
new_filename = numbering + " - " + names.values.sort[counter]
puts "New file name: " + new_filename
File.rename(f, folder_path + "/" + new_filename + File.extname(f))
counter += 1
end
puts "Renaming complete."
The output of new_filename is correct, e.g. "Foo - Bar: Foo.txt". When it renames the file, the file has following format: "Foo - Bar/ Foo.txt".
I tried escaping with the colon with a backslash, but doesn't seem to work, because my output then looks like this: "Foo - Bar/\ Foo.txt".
Is is possible to have a colon in a string for renaming files?

FYI - in NTFS a colon identifies a separate stream of the same file... "Foo Bar: Foo.txt" identifies file "Foo Bar", stream " Foo.txt". Reference "Alternate Data Streams" (currently http://support.microsoft.com/kb/105763). AFIK this feature is not really widely used, though I have seen it used to tag files with thrid-party data (I use it to store a file's sha1 for dupe identification under the stream *:sha1).

Related

rename files with Ruby

I'm trying this script to rename a series of files with unwanted characters:
$stdout.sync
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir['*'].each do |file|
# Skip directories
next unless File.file?(file)
old_name = File.basename(file,'.*')
if old_name.include?(search)
# Are you sure you want gsub here, and not sub?
# Don't use `old_name` here, it doesn't have the extension
new_name = File.basename(file).gsub(target,replace)
File.rename( file, new_path )
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
I would like to be able to pass as a prompt argument the path of the directory that contains the files to be renamed, and then I modified the script as follows:
$stdout.sync
path = ARGV[0]
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir[path].each do |file|
# Skip directories
next unless File.file?(file)
old_name = File.basename(file,'.*')
if old_name.include?(search)
# Are you sure you want gsub here, and not sub?
# Don't use `old_name` here, it doesn't have the extension
new_name = File.basename(file).gsub(target,replace)
File.rename( file, new_path )
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
get this error message:
renamefiles.rb:3:in `gets': Is a directory # io_fillbuf - fd:7
why?
When you pass an argument such that ARGV is populated the ruby interpreter will assume you mean Kernel#gets which expects a filename.
You should be able to fix this by using STDIN.gets so you would have
print "Enter the file search query: "; search = STDIN.gets.chomp
print "Enter the target to replace: "; target = STDIN.gets.chomp
print " Enter the new target name: "; replace = STDIN.gets.chomp
I have refined the code so that the file extension is not changed, and the directories are also renamed.
I have two problems left to solve:
-the passage of the path from argv (the path is not correctly recognized)
-I would like to recursively rename, even files in directories
path = ARGV[0]
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir::chdir('/Users/dennis/Documents/test/daRinominare')
Dir['*'].each do |file|
#puts file
if Dir.exist?(file)
directoryList = file
old_name = File.basename(file)
new_name = old_name.gsub(target,replace)
File.rename( file, new_name)
end
next unless File.file?(file)
old_name = File.basename(file,'.*')
extension = File.extname(file)
if old_name.include?(search)
new_name = old_name.gsub(target,replace) + extension
File.rename( file, new_name)
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
Kernel.gets reads from ARGF, which acts as an aggregate IO to read from the files named in ARGV, unless ARGV is empty in which case ARGF reads from $stdin. ARGF.gets will generate errors like EISDIR and ENOENT if ARGV has entries which are paths to directories or paths that don't exist.
If you want to read user input, use $stdin.gets
(The difference between $stdin and STDIN: The constant STDIN is the process standard input stream, and is the initial value of the variable $stdin which can be reassigned to change the source used by library methods; see globals. I use $stdin unless I need to change $stdin and also use STDIN for another purpose.)

File.exist? always returns false even when file does exist

I have a program that tries to open a file:
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: ";
relPath = gets;
absPath = Dir.pwd << "/" << relPath;
if File.exist?(absPath) then
puts "File exists";
file = File.open(absPath, "r");
other code...
else
puts "File does not exist";
end
It always prints "File does not exist" even when the current directory exists and the file also exists. The file and script are in the same directory.
I am running it on Mac OS X Yosemite (10.10.3) and Ruby 2.2.0p0.
I can't explain why (albeit I have strong belief that it's for some whitespace characters) but with this little contribution it works ok.
Dir.chdir(File.dirname(__FILE__))
print "Enter file name:";
relPath = gets.chomp; #intuitively used this, and it wroked fine
absPath = File.expand_path(relPath) #used builtin function expand_path instead of string concatenation
puts absPath
puts File.file?(absPath)
if File.exist?(absPath) then
puts "File exists";
puts File.ctime(absPath) #attempting a dummy operation :)
else
puts "File does not exist";
end
runnning code
$ ls -a anal*
analyzer.rb
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
ziya#ziya:~/Desktop/code/ruby$ ruby fileexists.rb
Enter file name:analyzer.rb
/home/ziya/Desktop/code/ruby/analyzer.rb #as a result of puts absPath
true #File.file?(absPath) => true
File exists
2015-06-11 12:48:31 +0500
That code has syntax error ("if" doesnt need "then"), and you dont have to put ";" after each line.
try
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: "
relPath = gets
absPath = "#{Dir.pwd}/#{relPath.chop}"
if File.exist?(absPath)
puts "File exists"
file = File.open(absPath, "r")
else
puts "File does not exist"
end
remember that gets will add a new line character so you will need to do a chomp, and that way to concatenate string won't work on ruby.
Your code is not idiomatic Ruby. I'd write it something like this untested code:
Dir.chdir(File.dirname(__FILE__))
puts 'Enter file name: '
rel_path = gets.chomp
abs_path = File.absolute_path(rel_path)
if File.exist?(abs_path)
puts 'File exists'
File.foreach(abs_path) do |line|
# process the line
end
else
puts 'File does not exist'
end
While Ruby supports the use of ;, they're for use when we absolutely must provide multiple commands on one line. The ONLY time I can think of needing that is when using Ruby to execute single-line commands at the command-line. In normal scripts I've never needed ; between statements.
then is used with if when we're using a single line if expression, however, we have trailing if which removes the need for then. For instance, these accomplish the same thing but the second is idiomatic, shorter, less verbose and easier to read:
if true then a = 1 end
a = 1 if true
See "What is the difference between "if" statements with "then" at the end?" for more information.
Instead of relPath and absPath we use snake_case for variables, so use rel_path and abs_path. It_is_a_readability AndMaintenanceThing.
File.absolute_path(rel_path) is a good way to take the starting directory and return the absolute path given a relative directory.
File.foreach is a very fast way to read a file, faster than slurping it using something like File.read. It is also scalable whereas File.read is not.

Rename all files in directory?

My task:
Write a program to rename files using regular expressions. This
program will take three command line arguments: the directory in which
to rename files, a regular expression that matches files to be
renamed, and a string to replace the regular expression match. The
primary use is to change file extensions, but it should be able to
handle replacing any portion of the file name.It should run as
follows:
./fixname.rb dir 'pattern' replacement
The program I have written is:
puts "Renaming files..."
folder_path = ARGV[0]
reg_exp = ARGV[1].to_regexp
Dir.glob(folder_path + "/*").sort.each do |f|
filename = File.basename(f, File.extname(f))
myString = String.new
myString = filename
filename = myString.gsub(reg_exp, ARGV[2])
#puts myString
File.rename(f, folder_path + "/" + filename + File.extname(f))
end
puts "Renaming complete."
The rename doesn't happen when I am using regexp, otherwise it is working. I'm getting:
error "`gsub': no implicit conversion of nil into String (TypeError)"
What you think is a regex is not, it's a String containing a regex pattern.
You need to convert that to a Regexp object. How to do that is left to you.

Regex on directory for linux

I have tried the regex from the answer of this question: check directory path for symbols range and ".." up directory sign
Which was not working for me. If I passed my script a directory like this "/home/local/NKU/dixonc3/test/" it would not match the regex.
So I just tried to start out with something simple such as if a directory starts with a slash / or a tilde ~ it will pass.
^[~/].*$
even when I use this as my regex in the code below if I pass it a ~ tilde it gives me an error
./rename.rb:23:in `exists?': can't convert nil into String (TypeError)
from ./rename.rb:23:in `rename'
from ./rename.rb:33:in `<main>'
Below is my Ruby code
currDir = ""
#
# regex is from stack overflow question:
#dirRegex = Regexp.new '^(?!.*[\\/]\.{2}[\\/])(?!\.{2}[\\/])[-\w.\\/]+$'
dirRegex = Regexp.new '^[~/]*$'
if ARGV.length == 1 && ($1.to_s.match dirRegex)
currDir = $1
puts $1
puts "#{currDir}"
puts ARGV.length
else
currDir = "./"
puts $1
puts "#{currDir}"
puts ARGV.length
end
Your regex is matching on a single character (~ or / or nothing). It should be:
dirRegex = Regexp.new '^[~/].*$'
To match on an opening character of ~ or / and the rest.

How to rename a file in Ruby?

Here's my .rb file:
puts "Renaming files..."
folder_path = "/home/papuccino1/Desktop/Test"
Dir.glob(folder_path + "/*").sort.each do |f|
filename = File.basename(f, File.extname(f))
File.rename(f, filename.capitalize + File.extname(f))
end
puts "Renaming complete."
The files are moved from their initial directory to where the .rb file is located. I'd like to rename the files on the spot, without moving them.
Any suggestions on what to do?
What about simply:
File.rename(f, folder_path + "/" + filename.capitalize + File.extname(f))
Doesn't the folder_path have to be part of the filename?
puts "Renaming files..."
folder_path = "/home/papuccino1/Desktop/Test/"
Dir.glob(folder_path + "*").sort.each do |f|
filename = File.basename(f, File.extname(f))
File.rename(f, folder_path + filename.capitalize + File.extname(f))
end
puts "Renaming complete."
edit: it appears Mat is giving the same answer as I, only in a slightly different way.
If you're running in the same location as the file you want to change
File.rename("test.txt", "hope.txt")
Though honestly, I sometimes I don't see the point in using ruby at all...no need probably so long as your filenames are simply interpreted in the shell:
`mv test.txt hope.txt`
If you are on a linux file system you could try mv #{filename} newname
You can also use File.rename(old,new)
Don't use this pattern unless you are ready to put proper quoting around filenames:
`mv test.txt hope.txt`
Indeed, suppose instead of "hope.txt" you have a file called "foo the bar.txt", the result will not be what you expect.

Resources