Solved

replace space to underscore in filenames on hard disk

Posted on 2010-09-01
29
2,756 Views
Last Modified: 2012-05-10
Hi

I have a folder on the hard disk. Folder contains 4000 files having spaces in between in the filenames. i want to replace spaces with underscore in the filenames. How can i do that with singale batch file
0
Comment
Question by:Saroj13
  • 10
  • 9
  • 3
  • +4
29 Comments
 
LVL 68

Accepted Solution

by:
Qlemo earned 500 total points
ID: 33581850
In a batch file:

@echo off
setlocal EnableDelayedExpansion
for %%F in ("c:\PathToFolder\* *") do (
   set name=%%~nF
   ren %%F "%%~dpF!name: =_!%%~xF
)
0
 
LVL 32

Expert Comment

by:aleghart
ID: 33581852
No need for a batch file.  Just ReNameIt.

http://sourceforge.net/projects/renameit/

I've used this for a while...takes 5 minutes to learn how to use it.  Great for naming sequential file numbers, changing date codes, renaming all the "PIC_XXX" or "IMG_XXX" files from a digital camera.

It has a preview mode, so you can see how the logic rules you just made will react.
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33581855
(I didn' test that - please try on a test folder)
0
 

Author Comment

by:Saroj13
ID: 33581861
Its not possibel to rename 4000 files maually
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33581874
Both solutions are working for a big set of files.
0
 
LVL 32

Expert Comment

by:aleghart
ID: 33581929
>Its not possibel to rename 4000 files maually

Software will take your rules, show you a preview of the file names, then let you execute.
ee-Rename-It.jpg
0
 
LVL 14

Expert Comment

by:Michael Dyer
ID: 33582019
Well, if this is a one time clean up, you could manually create a batch file with every file rename command on a single line.  

From the command prompt, type dir > names.txt /N
open a blank workbook in EXCELL.  import names.txt as a Delimited file with a space delimiter
clean up the top and bottom so you just have a column of the file names
insert a column before the file names and fill it with the value "ren"  
copy the two columns with the file names into two new columns to the right of the existing ones with an empty column in between.  Insert a column between the two pieces of the second column name and fill that column with $.  Also insert a column before the first part of the first file name with a % in it, and a column after the second part of the file name with a # in it.

It should look like this:

     ren % test 1.txt % test # 1.txt
     ren %' test 2.txt % test # 2.txt

Now, save this as a DOS csv file and open that file in notepad.  it should now look like this:

ren,%,test,1.txt,#',.test,$,1.txt
ren,%,test,2.txt,#,.test,$,2.txt

First use, Edit, Replace all to clean up the file.
Replace all %, with '
Replace all ,# with '
Replace all space$space with an Underscore.  
Now replace all remaining commas with a space.  The file should now look like this

ren 'test 1.txt' test_1.txt
ren 'test 2.txt' test_2.txt

now, just rename this with a .bat extension and run it to rename every file in the directory.

Of course, back up everything first, just in case.

Good Luck!
0
 
LVL 14

Expert Comment

by:canali
ID: 33591958
Try this!
Nice rename-it but with batch you can do more ;)

Ciao Gastone Canali
@echo off

::::::::::::::::::::::::::::: 

:: changeSpace2_.cmd

:: replace spaces with underscore in the filenames

:: Bye Gastone Canali

:::::::::::::::::::::::::::::

setlocal

set TargetDir="c:\folder\where files are"

if not exist %TargetDir% (echo ERROR:Folder not found & goto :_END) else cd  %TargetDir% 



for /f "tokens=*"   %%f in ('dir "* *" /b /A-D') do call :_rename "%%f"  



goto :_END

:_rename 

   set FileName=%~1

   set NewName=%FileName: =_%

   rem ****************************************************

   rem *** remove the ECHO to activate it                **

   rem ****************************************************

   ECHO ren "%FileName%"  "%NewName%"

   

goto :_EOF

   

:_END

:_EOF

Open in new window

0
 
LVL 32

Expert Comment

by:aleghart
ID: 33592118
>with batch you can do more ;)

Well, you're not here at 3am to write BATch scripts for me.  So, I'll keep Rename-It handy.  :)
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33592261
@canali:
Ehem. The nice thing with my batch file was that is is small.
And, seriously, don't GOTO to the end of the file. That is so out-dated :P. You can use exit /b 0, which even allows to return an errorlevel (of 0 in this case).

And, as I'm at it, goto :...  isn't a valid syntax (I know it works, but that is a flaw rather than a feature). Omit the colon to get a certified syntax.

And if you want to go to the end of file nevertheless, the predefined label :EOF can be used in GOTO (this time the colon is syntactically correct) without need to define that label.
0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33601854
I think you should do it this way with 4000 files the fewer lines which execute the better!

I would really suggest doing it without anything more than a single line.  Also in this batch file, I used a completely unnecessary set command for the parth so it would be simpler to follow.  I will re-post after this with the single-line solution.

~Q

@ECHO OFF&SET "TPath=C:\Folder1\Folder 2\Folder Of Files"
:Main
MOVE /Y "%TPath%\%TName%" "%TPath%\%TName: =_%"&FOR /F "Tokens=*" %%A IN ('DIR "%TPath%\* *" /A:-D /B') DO SET "TName=%%A"&CALL :Main

Open in new window

0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33601876
If you do it this way it will be faster but you will need to edit the batch file to point back to itself to achieve the recursion we're looking for.

   I think this is your best bang for the buck.

NOTE:  you may be able to save a modicum of time if you remove the GOTO :EOF, but it will finish doings and then keep running as it leaves the recursion, also that will cause additional memory usage, so I suggest you leave it, up to you of course.


@ECHO OFF&MOVE /Y "C:\Folder1\Folder 2\Folder Of Files\%TName%" "C:\Folder1\Folder 2\Folder Of Files\%TName: =_%"&FOR /F "Tokens=*" %%A IN ('DIR "C:\Folder1\Folder 2\Folder Of Files\* *" /A:-D /B') DO SET "TName=%%A"&CALL "C:\Admin\RecursRen.bat"&GOTO:EOF

Open in new window

0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33602547
QCubed,

Sorry having to say that, but that's an inappropriate approach for several reasons:
  • TName is not defined the first time the batch file is executed. The move command will try to rename the file called "%TName%", which results in an error (file not found).
  • move has no advantage over ren in this case, but vice versa: with ren you need to name the folder only once, which makes the code shorter and less prone to typos.
  • move /y is dangerous - if there are name conflicts, you loose the previous version of the file.
  • You might run into stack issues very fast with the unwanted and unnecessary recursion, if applied to thousands of files. For this particular part you just need to remove the call (but still execute the batch) and the GOTO
  • The recursion/iteration approach will call dir in each (!) go. With 400 files, that is a listing of 400+399+398+... = (400+1)*200 = 80200 files. Though each listing should be resolved using the cache in not too much time, it remains unnecessary.
The following code applies that all (but the last point). Because of the last issue I would not go that course. If you need to use a batch file anyway, my approach is more straightforward and performs much better. Slightly modified, it would even work for files in subfolders containing spaces.


Saroj,

Rename-It is useful when you need to do it as an one-timer, or on rare occassions. It has the advantage that you can preview what you want to do, which is much safer.

The batch file approach can be applied in that case too, but it is much more indicated if you want to rename regularly the same way ("try once - use often").

@ECHO OFF & cd /D "C:\Folder1\Folder 2\Folder Of Files" & REN "%TName%" "%TName: =_%" 2>nul & FOR /F "Tokens=*" %%A IN ('DIR "* *" /A:-D /B') DO SET "TName=%%A"  &  "C:\Admin\RecursRen.bat"

Open in new window

0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33603856
Hey Qlemo, there is actually a certain method to my madness.

TName isn't defined the first tiem the bacth file executes, because we haven't done the for-loop yet, unless a file is literally named the string "%TNAME%" the command will error harmlessly, yes you will have a needless echo to screen the first time through of the harmless error.  if that bothers you we could use 2> nul on the command but that seems excessive to me

I chose move because is that a specific advantage over REN in that it can operate on read-only files when the /Y switch is supplied.  I agree ren has a shorter method not needing the path twice.

While correct that Move is "dangerous" if the destination file exists it would be overwritten, it seems this would be unlikely unless the Author already had similarly named files.  The Ren option would error harmlessly in those cases then we should output a log making this a slower operation.

  However using MOVE we could easily solve this by moving the file to a different directory in reality say sub dir 'cng'.

 while we could add the MD it woudl be best to create it before hand instead of having the needless command in the batch. further more so is we should really stick our "echo off" CMD on the initial calling of the command so that we don't waste time with it needlessly executing each go-round.

The GOTO Cmd was intended to kill the current dir list to save on stack, but your right I've already instantiated and done the dir, and WHY even Re-do that work in the first place?

Also note that your batch file is still causing a recursion by placing the command name without the call, and you still will cause the same problem with stack overflow, and if you did want to use it as -stands then the &GOTO :EOF would still be required.


However I admit my mistake, it was quite late and I should have thought of the possibility of stack over-flow.

Here I have properly corrected the command to be a single line without causing a stack overflow by exiting all subsequent calls to the batch file without calling another dir command or recurring a second time.

Also I have and removed the ECHO Off command and the %TName% variable needs to be set to a default variable previous to the file execution, for it to work properly. I felt this was better than having the batch file set an extra variable once on the first time through so that all of that happens externally and it's only used the one time.  but the command is definitly shorter this way

Also note you are CDing, using a direct file path or running the batch file int he same directory as the files to be processed would be the best options if you really want to remove the need for a file path to further reduce the footprint of the text int he batch file for ultimate efficiency.

but of course the more I think about tit the more I should stuff everything inside the if that runs the one time because the external command to call the code attached does get a bit lengthy needing to be:

ECHO OFF&SET "TName=NOMATCH"&"C:\Admin\RecurseRen.bat"&ECHO ON

MOVE /Y "C:\test\%TName%" "C:\test\%TName: =_%"&IF /I "%TName%"=="NOMATCH" FOR /F "Tokens=*" %%A IN ('DIR "C:\test\* *" /A:-D /B') DO SET "TName=%%A"&CALL "C:\Admin\RecurseRen.bat"

Open in new window

0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 11

Expert Comment

by:Ben Personick
ID: 33603943
that being said here it's all self contained. and no need for the extr stuff on the outside.  Of course you can only run it once and then you have to set the temp variable to a different value or change the variable name used  ^^

@MOVE /Y "C:\test\%TName%" "C:\test\%TName:_= %"&IF /I "%tmst%" NEQ "NOREPEAT" SET "tmst=NOREPEAT"&FOR /F "Tokens=*" %%A IN ('DIR "C:\test\*_*" /A:-D /B') DO @SET "TName=%%A"&CALL "C:\Admin\RecurseRen2.bat"

Open in new window

0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33604108
okay I also took the time to make it truly self contained =)  the only thin you will need to do is specify the path to the folder, and a value to use to for the temp variable to keep you from dir looping =)

Call like this:

C:\Admin\rn.bat "C:\test" "A"

@MOVE /Y "%~f1\%NM%" "%~f1\%NM:_= %"&IF /I "%TM%" NEQ "%~2" SET "TM=%~2"&FOR /F "Tokens=*" %%a IN ('DIR "%~f1\*_*" /A:-D /B') DO @SET "NM=%%a"&@CALL "%~f0" "%~f1" "%~2"

Open in new window

0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33604627
The Ren option would error  harmlessly in those cases then we should output a log making this a  slower operation.

ren would error if the file exists - the message is written to stderr, which can easily be logged without adding to the execution time, since only errors would be logged.

Also note that your batch file is still causing a recursion by placing the command name without the call, and you still will cause the same problem with stack overflow, and if you did want to use it as -stands then the &GOTO :EOF would still be required.

Wrong. If we omit CALL, it is no recursion anymore, it is an iteration - the batch file is replaced by itself, and no return is possible, so no stack here. The "overly run DIR" issue still remains, however.

Further, somewhere on the way to the last posts you exchanged the space and underscore. The files have spaced, and need to be renamed using underscores, not vice versa.
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33604631
Saroj,

it is time for you to post ... Did we loose you? Are you interested in following that approach QCubed shows?
0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33604755
Actually, I tried it with and without the "Call" to see if that might be a cheaper method to handle the process, but, I assure you in both cases it caused a stack over-flow, the only difference is without the call the batch does not instantiate a new command prompt, and therefore the CMD cannot catch the overflow, and the COMMAND will just crash as a non responcive process instead of echoing the stack over-flow issue, and killing the iterations so that you could re-run it.  Try the code.

Regardless of whether you want to call this recusion or not, the point had always been to kill the DIR process, as I perhaps did not say clearly enough, I went about terminating things wrong on the initial script.

I solved that in my next posted script.  I don't dispute the multi-dir would have been a problem, which I was trying not to have, but it's fixed. Since you pointed it out that I had the very issue I intended to avoid late last night I was obsessively working on making the whole process lighter and faster this AM  
And I already thought of another iteration to post that would be better that even the last one, not needing an input for the variable match at all.

However being at a Bridal shower IDK that I couldcode it right in my head on the BB, I'll try to post it later.

I also wanted to say you were right, we can just us REN, I sucessfully used REN to rename a read-only file. So I was mistaken that we HAD to use Move to get around Read-only files.

Also, yes, we could write a log of all errors, as I said it's quite easy to add, but writing to disk at all is slow, so we should avoid it, and simply run a DIR by hand afterward to find any files which did not change due to already existing, or, again for-go it entirely, and just use the move, that is a matter of whether there will be duplicates, and if they are what should be done though.

  My scrip will work nicely either way :)  

Also Sorry about the _ verses the space, I have been testing the batch by transforming files both from and to _ or a space per iteration so I don't have to recreate them ^^
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33604898
I *really* should have tested my script ... But that revision is working now:
@echo off

setlocal EnableDelayedExpansion

for %%F in ("c:\Path To Folder\* *") do (

   set name=%%~nF

   ren "%%~F" "!name: =_!%%~xF"

)

Open in new window

0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33604910
Regarding recursion/iteration: The following test can be run to test both cases. With call, a stack overflow happens at about 705 calls. Without call it runs endlessly.
Maybe the FOR or the particular command line you use caused the stack overflow - didn't test that.
@echo off

set /A i += 1

set /P @=%i% <nul

call %0 %*

Open in new window

0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33605019
Yes, the for loop is what causes a true recursion.  That was what I meant, you suggested I use no call in my loop but just use a command without a call, that will still cause a recursion, if there is no loop, then calling the other batch would be linear instead of recursive, or at least cause far less foot-print per iteration by letting the dir resolve.
That's why I only call dir in the first iteratio, that is the best of boath worlds.

 However I did resolve the recursion issue on the next iteration, I should always have done it that way.
0
 
LVL 51

Expert Comment

by:Bill Prew
ID: 33605153
Not that anybody really cares, and I love both you guys, but I think I prefer the Qlemo approach.  It seems obvious, easy to read and reasonably to the point.  While it may run a little slower than the single line approach (although it could be done all on one line as well), I imagine this rename is a one time effort, so I doubt that performance trumps readability and simplicity in this case.

A couple of things the poster hasn't clarified that could change the approach are:

(1) are all files in the base folder, or are there subfolders?

(2) are there ever 2 or more contiguous spaces in the file names, and if so should each space be replaced by an underscore, or should contiguous spaces be replaced by a single underscore?

(3) can the spaces ever occur in the extension, or not?

~bp
0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33605579
Okay, home now, the attached code is 1 line, 143 characters.  It won't cause a stack over-flow as that was solved many posts ago, should be super fast, and you specify the path to run it against as the only parameter it needs entered.

Bill you bring up some good points.

  •  As for readability, with so many files, and the fact that it probably won't be re-used again, I think it makes more sense to code for speed instead of re-usability or ease of editing, however in my newest iterations you don't change the commands int he batch file at all only changing the input on the command line.
  •  In fact as in this newest iteration you would not do anything to the batch file at all only specifying the path to the files =) and it uses 99% the implicit  variables %0, %1, %2 %a Instead of explicit variables (can't get pas needing one for the rename itself unfortunately.  So mores the better for speed.
  • As for sub directories I also had the thought that there may be sub directories.  However my script will work perfectly in that instance if we simply add a /S to the DIR command. =)
  • As for the possibility the author wants to turn multiple spaces into a single underscore I had NOT considered that, it definitely wasn't part of the question as posted, and would definitely take retooling coding on all of our scripts. DEFINITELY Worth asking though!!
Also it's been a very stimulating conversation with Qelmo, as I've mentioned in other posts on these Forums I really respect both you and Qelmo's experience and input, you guys are TOPS!! =)

 Qelmo if not for your pointing out the mistake of my first batch file I wouldn't ever have spent so much time trying to first solve the issue, and focusing on how the whole point of calling was to make the tighter script and use the implicit variables instead.

  Thanks you so much Qelmo for pushing me to get such a tight piece of code! =)  I've been really turning it over in my head a lot because of you!  and it came out pretty darn concise!

@REN "%~f1\%NM%" "%NM: =_%"&IF /I "%~2" NEQ "A" FOR /F "Tokens=*" %%a IN ('DIR "%~f1\* *" /A:-D /B') DO @SET "NM=%%~nxa"&CALL "%~f0" "%~f1" "A"

Open in new window

0
 
LVL 11

Expert Comment

by:Ben Personick
ID: 33605591
Here is the script if it needs to also work through sub directories under the initial directory.

both the last script and this one should be called by the name you save the script as (it can be named whatever you like) and the path to the files that need to be renamed


 eg: For a script named rt.bat in a folder called c:\admin  and I will run the batch against c:\test\test2
"C:\Admin\rt.bat" "C:\test\test2"

@REN "%~f1\%NM%" "%NM: =_%"&IF /I "%~2" NEQ "A" FOR /F "Tokens=*" %%a IN ('DIR "%~f1\* *" /S /A:-D /B') DO @SET "NM=%%~nxa"&CALL "%~f0" "%~f1" "A"

Open in new window

0
 
LVL 14

Expert Comment

by:canali
ID: 33607853
@Qlemo:
>Ehem. The nice thing with my batch file was that is is small.
 my is longer! ;)
>And, seriously, don't GOTO to the end of the file. That is so out-dated :P.
 Probably because I have  (some) white  hair,  1 wife 2 sons ...
>You can use exit /b 0, which even allows to return an errorlevel (of 0 in this case).
 exit is boring ... always close my little black window.
>And, as I'm at it, goto :...  isn't a valid syntax (I know it works, but that is a flaw rather than a feature).   Omit  the colon to get a certified syntax.
 this is my sign..
>And if you want to go to the end of file nevertheless, the predefined label :EOF
 I don't stop to learn (next time I will leave the :_EOF for readibility)

and this is your script without bug ( you loose a " )
@echo off
setlocal EnableDelayedExpansion
for %%F in ("c:\PathToFolder\* *") do (
   set name=%%~nF
   ren %%F "%%~dpF!name: =_!%%~xF"
)
 
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 33607914
@Canali:
> exit is boring ... always close my little black window.
Yes, if you do not add the /b switch!

> and this is your script without bug ( you loose a " )
I already corrected that in http:#a33604898. You are too slow, White Hair with Many Sons :D
0
 
LVL 14

Expert Comment

by:canali
ID: 33615881
@Qlemo:
   Touche
0
 

Author Closing Comment

by:Saroj13
ID: 33746690
solves problem
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

YESTERDAY YESTERDAY.BAT is inspired by a previous article I wrote entitled: TOMORROW.BAT (http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/MS_DOS/A_4196-Advanced-Batch-File-Programming-TOMORROW-BAT.html). The crux of this batch f…
I have published numerous articles here at Experts Exchange that present programs/scripts written in a language called AutoHotkey. Each of those articles has a brief paragraph describing where to download the product and how to install it. I have al…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now