# How to batch rename a directory of files?

I have a directory of files with the pattern: "some_number.some_name.pdf" I want to remove the "some_number." part from all the files. How to do that? There are a few commands in my head: FileNames, Map, etc. But I don't know how to chain them together to achieve the task.

-
Try ?Rename*; ?StringR* and give it a shot. Its not a very difficult problem really. –  chris Nov 19 '12 at 21:59
Other useful functions involve ?Regular* –  chris Nov 19 '12 at 22:12

As I mentioned in a comment, using string patterns makes for lot cleaner code. Here's a simple way to do it using StringCases:

changeFileName = StringCases[#, NumberString ~~ "." ~~ f__ :> f] &;
changeFileName@"1234.name.pdf"
(* {"name.pdf"} *)


If you have a list of file names, map the above onto the list.

You can progressively build upon this for more complicated filename patterns. However, for the requirements in the question, this is adequate.

-

A pure function to make the changes to a filename string:

 fileNameChangeF = StringJoin@ Riffle[
Pick[#, StringFreeQ[#, __ ~~ "_" ~~ NumberString] & /@ #] &@#,"."] &@
StringSplit[#, "."] &


example:

 filenameList = {"abc_1234.xyz_name1.pdf",   "abc_1234.xyz_222.aaa_name2.pdf",
"some_name.pdf"}
fileNameChangeF/@filenameList
(* {"xyz_name1.pdf", "aaa_name2.pdf", "some_name.pdf"} *)


EDIT: what the function does step-by-step:

 filenameList[[1]] (* input filename string *)
(* "abc_1234.xyz_name1.pdf" *)
StringSplit[#, "."] &[%] (* split at "."s *)
(* {"abc_1234","xyz_name1","pdf"} *)
StringFreeQ[#, __ ~~ "_" ~~ NumberString] & /@ %
(* find the parts free of the pattern *)
(*{False,True,True} *)
Pick[%%, %] (* pick those parts *)
(* {"xyz_name1","pdf"}*)
Riffle[%, "."] (* insert "."s back in *)
(* {"xyz_name1",".","pdf"} *)
StringJoin[%] (* ... and join *)
(* "xyz_name1.pdf" *)


Mapped to a list of filenames fileNameChangeF/@filenameList, it does the same operations on each filename.

-
obviously a good answer but pretty scary nonetheless! –  chris Nov 19 '12 at 22:20
Wow when i fully understand this oneliner i'll learn some good stuff from Mathematica. Thanks ! –  user4714 Nov 19 '12 at 22:22
@chris, updated to make it dispell the scare :) –  kglr Nov 19 '12 at 22:36
@kguler have you ever considered competing for the one-liner competition? :-) –  chris Nov 19 '12 at 22:39
For guys who like regexes: RegularExpression["(?s).+_(\\d)+"] –  Guess who it is. Nov 19 '12 at 22:46

Here's how I'd do it. Hopefully it's general enough, and easy to understand.

Start by defining a base directory:

 base = "c:\\mse\\test\\";


I usually use Import to get a list of filenames. If you give it a directory name, it will return a list of all the files under that directory (including subdirectories):

original = Import[base]


{"1.alice.pdf", "2.bob.pdf", "30.charlie.pdf"}

Then we can use a string expressions and a rule to transform the names:

renamed = StringReplace[original, NumberString .. ~~ "." ~~ name__ ~~ ".pdf" ->
name ~~ ".pdf"]


{"alice.pdf", "bob.pdf", "charlie.pdf"}

Finally take the two lists and rename the files. It's probably clearest to use a Table:

Table[RenameFile[base <> original[[i]], base <> renamed[[i]]], {i, Length[original]}]

-
For regex fans: StringReplace[original, RegularExpression["(\\d)+\\."] -> ""] –  Guess who it is. Nov 20 '12 at 0:05

Just for guidance, you could

SetDirectory["~/tmp/"]

ff = FileNames["*.pdf"]

{01.toto01.pdf,02.toto02.pdf}


Try it with a fake function to be sure

Map[RenameFile1[#, StringDrop[#, 3]] &, ff]


If it does what you want do it for real

Map[RenameFile[#, StringDrop[#, 3]] &, ff]

-
I would rather use string patterns to drop the prefix instead of StringDrop. The latter assumes that all prefixes are of the same length, which may not be true. –  The Toad Nov 19 '12 at 22:09
@rm-rf sure. I would rather not do it myself though and let the OP do what he wants ;-) Feel free to edit/remove my answer in any case. –  chris Nov 19 '12 at 22:10
@chris He may have more than 99 pdf files in his directory. I recommend StringTake[#, First@First@StringPosition[#, "."] - StringLength[#]] & –  VF1 Nov 19 '12 at 22:12
How to use string patterns to do this ? –  user4714 Nov 19 '12 at 22:13
@user4714 I don't see why you would use patterns, since the numbers are always at the beginning of the string. There's no need to always use pattern matching. –  VF1 Nov 19 '12 at 22:13