0

What is an efficient way to rename files in OSX/BSD from a text file for files assumed to stay in original folder, but in the format of;

/path/old file name.ext\tnew file name.ext

There may be say thousands of entries using TAB delimiter between entries.and any line delimiter used in Windows,OSX or Linux.

File names may contain any valid character including _'!?~*&^%$#@,.∑´®†¥¨ˆ¬˚∆˙©ƒ & Asian font characters

Names end with a dotted extension e.g. .xxx.

12
  • How are "old file name" and "new file name" separated? Are those file names allowed to contain spaces?
    – slhck
    May 20, 2012 at 15:34
  • I think a reverse parse of the string might extract the end of the folder path from the last entry of "/" to a variable so it can be used in a valid syntax for BSD using mv %path/%oldname %path/%newname , so that may require some smart script parsing. I am BSD challenged at the moment. May 20, 2012 at 15:43
  • You didn't answer my question. Is there a space separating the entries? If yes, can we assume the entries themselves contain no spaces at all? If not, is there a \t between the entries, or something else to split the entries at?
    – slhck
    May 20, 2012 at 15:47
  • File names are separated with at least 1 space, but then so are words within a file name, so the only distinction is that names end with a dotted extension e.g. .xxx May 20, 2012 at 15:48
  • That's a really bad format to work with.. oh well. Is it at least one space or one space exactly? Are the extensions of the same size (i.e. three characters)? Do all files have an extension? (Sorry that I ask so much, but you gave us not a lot to work with …)
    – slhck
    May 20, 2012 at 15:54

1 Answer 1

2

Updated version:

This one takes as specification:

  • Each statement on one line
  • Records are separated by a \t character.

That makes it much easier:

require 'fileutils'
File.open("input.txt", 'r').each_line do |l|
  next if l.strip.empty?
  f = l.split("\t")
  dir = File.dirname f[0]
  if File.exists? f[0]
    p "Moving #{f[0]} to #{dir}/#{f[1].strip}"
    # FileUtils.mv f[0], "#{dir}/#{f[1].strip}"
  else
    p "#{f[0]} does not exist."
  end
end

Save this as a file and call it with ruby filename.rb. It'll read from input.txt in the same directory and just move the files.

Uncomment the # FileUtils… line for it to actually move something. This should tell you if the original file can't be found.


Your original input specification was:

  • Each statement on one line
  • Records are not terminated or separated except for their extension
  • Records can contain spaces, and delimiter can be multiple spaces ("at least 1 space")

One therefore has to fall back to matching the first file extension, then interpreting this as the first argument. Then, we need to remove this part from the original line, remove beginning and trailing whitespace, and construct the mv command.

Additional assumptions:

  • All extensions have only three characters, not more, not less
  • The file names themselves don't contain a dot (otherwise this breaks)

Since you're on OS X, let's just use Ruby:

require 'fileutils'
File.open("input.txt", 'r').each_line do |l|
  next if l.strip.empty?
  old_file = l[0, l.index(/\.[a-z0-9]{3}/i) + 4]
  dir = File.dirname old_file
  new_filename = l.sub(old_file, '').lstrip.chomp
  p "Moving #{old_file} to #{dir}/#{new_filename}"
  # FileUtils.mv old_file, "#{dir}/#{new_filename}"
end
16
  • tony.rb:2: undefined method +' for nil:NilClass (NoMethodError) from tony.rb:1:in each_line' from tony.rb:1 May 21, 2012 at 4:37
  • @TonyStewart Some line in the input probably didn't contain \.[a-z]{3}. Try running it on a subset of lines in the input or removing empty lines.
    – Lri
    May 21, 2012 at 8:06
  • This challenge becomes even more difficult when you consider the depth of filename specs and incompatibilities across platforms but I choose to *ignore that for now.. e.g Chinese font text and RTL Language fonts May 21, 2012 at 16:30
  • nope>> ruby tony.rb tony.rb:2: undefined method +' for nil:NilClass (NoMethodError) from tony.rb:1:in each_line' << I agree it is insane. I could do it in excel using string match for file extensions using a common set of a few .xxx and last occurrence of / to denote beginning of file name.back in 3 hrs May 21, 2012 at 17:03
  • 1
    @TonyStewart Yeah, of course it won't work if there are numbers in the extension. You have to add 0-9 there, see my updated answer. Next time, please be way more specific with your requirements, else it's hard to diagnose or even answer to begin with. Good luck!
    – slhck
    May 22, 2012 at 7:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .