Batch script not processing files with () in name? - windows

I'm trying to rename all the files in a folder to a number, using this:
setlocal enabledelayedexpansion
set "count=1"
for /f %%f in ('dir /b /o:-d /tc *.jpg') do (
ren %%f !count!.jpg
set /a count+=1
)
pause
However, it is only applying this code to the files that do not have () in them. So a file like:
hello.jpg
works, whereas:
hello (0).jpg
does not get picked up. And googling batch script syntax is an exercise in frustration for some reason, so I cannot for the life of me figure out why it's only doing the former.

EDIT :
Just insert text in Double quotes.
Try my way :
#echo off
setlocal enabledelayedexpansion
set "count=1"
Rem Rem "%%~nxf" to get the filename only as described in the reference for for.
for /f "delims=" %%f in ('dir /b /o:-d /tc *.jpg') do (
for /F %%q in ("%%~nf") do (
REN "%%~nxf" "%%q (!count!).jpg"
)
set /a count+=1
)
pause

I suggest this batch file for renaming all JPEG files with case-insensitive file extension JPG in current folder with a number as file name incremented by one on each JPEG file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileNumber=0"
set "TempRename="
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B /O-D /TC 2^>nul') do call :RenameFile "%%I"
if defined TempRename for /F "eol=| tokens=2 delims=_" %%I in ('dir !tmp_*.jpg /A-D /B') do ren "!tmp_%%I" "%%I"
goto :EOF
:RenameFile
set /A FileNumber+=1
if %1 == "%FileNumber%%~x1" goto :EOF
if not exist "%FileNumber%%~x1" ren %1 "%FileNumber%%~x1" & goto :EOF
ren %1 "!tmp_%FileNumber%%~x1"
set "TempRename=1"
goto :EOF
The execution environment is set up with the first two command lines which disable command echoing, enable command extensions as required for this batch file for several commands and with disabling delayed environment variable expansion to process correct also file names of JPEG files containing one or more exclamation marks.
Then the environment variable FileNumber is defined with value 0 and the environment variable TempRename is undefined if it is defined by chance on starting this batch file in local environment set up with command SETLOCAL.
Next the command process (cmd.exe) processing the batch file starts in background one more command process because of command FOR with option /F with a command line specified within ' by executing %ComSpec% /c and the command line in ' appended as additional arguments. So there is executed in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c dir *.jpg /A-D /B /O-D /TC 2>nul
The internal command DIR of cmd.exe searches in current directory for
only files because of option /A-D (attribute not directory)
matching the wildcard pattern *.jpg in long or short 8.3 file name
and outputs the found file names in bare format because of option /B which means only file name and file extension
ordered reverse by creation date which means the file name of the JPEG file created last in current folder is output first and the file name of the JPEG file created first in current folder is output last.
I don't know why the file creation date in current folder is used for this file renaming task and not the last modification date which does not change on copying or moving a file to another folder in comparison to creation date which is set new on a file is copied or moved to another folder. I also don't know why a reverse ordering is done.
2>nul is appended to the DIR command line to suppress the error message output by DIR if it cannot find any entry in current folder which meets the requirements, i.e. there is no *.jpg file in current folder at all, by redirecting the error message from handle STDERR of background command process to device NUL.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The output written to handle STDOUT of background command process is captured by FOR and processed line by line after started cmd.exe terminated itself after finishing execution of command DIR.
It is very important to process by FOR a list of file names loaded already completely into memory of command process as the task is to rename files in current folder. It would be not good for various reasons if just a simple FOR loop would be used as in this case the list of file names in current folder changes with each file rename done on iterating over the list of file names. That could cause that some JPEG files are not renamed at all, or are renamed more than once, or FOR becomes an even endless running loop depending on file system. NTFS adds file names different to FAT32 and exFAT to file names table of a folder resulting in different behavior on iterating over the files names of a folder matching a wildcard pattern.
FOR with option /F ignores empty lines which do not occur here and splits up each captured line into substrings using by default normal space and horizontal tab as string delimiters. The line splitting behavior on spaces is not wanted here and for that reason delims= is used to define an empty list of string delimiters to turn off line splitting behavior completely.
FOR with option /F would ignore lines on which first substring (entire file name on using delims=) starts with a semicolon. A file name can start with ; although this is very rare. Therefore eol=| redefines end of line option to a vertical bar which no file name can contain ever and so no file name is ignored by FOR.
The usage of delayed expansion must be avoided to process also successfully file names containing one or more ! which is the reason why the file name assigned currently to the loop variable I is passed enclosed in double quotes to a subroutine name RenameFile. The double quotes are required for file names containing a space or one of these characters &()[]{}^=;!'+,`~.
The subroutine uses first an arithmetic expression to increment the file number by one.
Then it checks if the current file name in double quotes is case-sensitive equal the new file name consisting of the current file number and the file extension of the file in which case the subroutine is left without doing anything at all for this file which has already the correct file name.
Otherwise it is checked if there is no file with new file name in current folder. The file is renamed if this condition is true and the subroutine is left.
The current file is renamed temporarily to !tmp_ and file number appended and keeping file extension if there is already in current folder a file with new file name which will be later renamed. So renaming of current file is more or less queued until all JPEG files in current folder have been processed at least once with renaming all files which could be renamed on first run. This solution works only if there are no file names matching the pattern !tmp_*.jpg in current folder on starting the batch file.
After first FOR processed all captured file names a second FOR is executed only if some file names could not be renamed directly which renames the temporarily renamed files to final file name.
The last command goto :EOF of main code avoids a fall through to code of the subroutine as explained in detail on Where does GOTO :EOF return to? and results in running implicit the command ENDLOCAL to restore initial execution environment explained in detail by this answer.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
ren /?
set /?
setlocal /?
Please note that %1 in subroutine RenameFile references the first argument string exactly as passed to the subroutine which means the file name of current file with the surrounding double quotes.
By the way: Shareware file manager Total Commander has built-in a multi-rename-tool which makes it possible to rename files and folders without having any programming skills and being nevertheless very powerful as even regular expressions can be applied on file names and the resulting file names are displayed before starting the rename operation. The multimedia viewer IrfanView being free for private usage has also a batch rename feature which makes it also possible to rename files without having any coding skills. IrfanView offers also the feature to use data stored inside a JPEG file like date/time on which a photo was made with a camera to put into the file name which would mean using real creation date/time of a photo instead of the date/time on which a file was created in current folder.

To directly do what you intend, we do not need to use set /a
#echo off
for /f "tokens=1* delims=[]" %%i in ('dir /b /o:-d /tc *.jpg ^| find /v /n "^"') do (
ren "%%~j" "%%~nj %%i%%~xj"
)
This does what you want, there is one problem though, if you run this a second time it will rename the same files again, appending yet another number to the name. There are a few ways to sort that out, this one for instance. Assuming your original file does not have numeric value at the end, separated by a space from the filename:
#echo off
for /f "tokens=1* delims=[]" %%i in ('dir /b /o:-d /tc *.jpg ^| find /v /n "^" ^| findstr /VIRC:" [0-9$]"') do (
ren "%%~j" "%%~nj (%%i)%%~xj"
)

Related

Using CMD on Windows to remove a specific substring from a directory of files

I frequently use a free online lossless file compressor to save space on my disk and make transferring and pushing repos easier. My main problem with the compressor is it appends "-min" to the end of every filename. For various reasons, I want to replace the original files by overwriting them; instead of deleting the old files and keeping the new files (with the "new" names).
For my PDF directory, I tried this:
FOR /R %f IN (*-min.pdf) DO REN "%f" *.pdf
And it seems to correctly find all the corresponding files, but their names remain the same. What am I doing incorrectly? Is there a single command that would be file-format-agnostic, so I wouldn't have to sub out the file extension for txt's, png's, etc?
I just need it to remove the -min from the end of each filename (before the file extension).
FOR /R %f IN (*-min.pdf) DO REN "%f" *.pdf
For a one liner (at the cmd prompt) remove echo from the following.
cmd /v:on /c "for /R %f in (*-min.pdf) do #set "nx=%~nxf" & echo ren "%~ff" "!nx:-min.pdf=.pdf!""
The above can be easily changed to perform other string manipulations, but it is not technically foolproof, for example it will rename a file named "a-min.pdf.b-min.pdf-c-min.pdf" to "a.pdf.b.pdf-c.pdf.". If that is a concern in this case, then use the following, which is essentially the same as in #Mofi's answer.
cmd /v:on /c "for /R %f in (*-min.pdf) do #set "nn=%~nf" & echo ren "%~ff" "!nn:~0,-4!%~xf""
The task can be done with a batch file with following command lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0*-min.*" /A-D /B /S 2^>nul') do (
set "FullFileName=%%I"
set "FileNameOnly=%%~nI"
set "FileExtension=%%~xI"
setlocal EnableDelayedExpansion
if /I "!FileNameOnly:~-4!" == "-min" ren "!FullFileName!" "!FileNameOnly:~0,-4!!FileExtension!"
endlocal
)
endlocal
The command DIR executed by a separate command process started by FOR in background with %ComSpec% /c and the command line between ' appended as additional arguments outputs also file names like Test-File!-min.x.pdf with full path. For that reason the IF condition makes sure to rename only files of which file name really ends case-insensitive with the string -min like Test-File!-MIN.pdf.
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~dp0 ... drive and path of argument 0 which is full path of the batch file which always ends with a backslash and for that reason concatenated with the wildcard pattern *-min.* without an additional backslash. %~dp0 can be removed to run DIR on current directory and all its subdirectories instead of batch file directory and all its subdirectories.
dir /?
echo /?
endlocal /?
if /?
ren /?
set /?
setlocal /?
See also this answer for more details about the commands SETLOCAL and ENDLOCAL.

How do I create folder from file name and move files into folder?

I need a windows batch file to create a folder based on part of a file name (the part before an underscore) and move any files that start with the folder name into the folder.
I'm not familiar with windows batch files. I've googled and tinkered a solution which works except that I cannot substring the file name at the underscore.
(Yes there are a few similar threads but nothing I could use to exactly answer my question)
FWIW my unsuccessful solution:
#ECHO OFF
setlocal enabledelayedexpansion
SETLOCAL
SET "sourcedir=C:\Development\test"
PUSHD %sourcedir%
FOR /f "tokens=1*" %%a IN (
'dir /b /a-d "TTT*_*.*"'
) DO (
ECHO MD NEED FILE NAME BEFORE UNDERSCORE HERE
ECHO MOVE "%%a" .\NEED FILE NAME BEFORE UNDERSCORE HERE\
)
(Ideally I'd remove the leading 'TTT' from files too but if necessary can create the files without this.)
Try this batch file code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do (
md "%DestDir%\%%B" 2>nul
move /Y "%SourceDir%\%%A" "%DestDir%\%%B\"
)
)
endlocal
The first FOR executes in a separate command process started with cmd.exe /C in background the command line:
dir /B /A-D-H "C:\Development\test\TTT*_*" 2>nul
DIR searches in specified directory for
just non-hidden files because of /A-D-H (attribute not directory and not hidden)
matching the wildcard pattern TTT*_* which could be also just *_*
and outputs to handle STDOUT in bare format because of /B just the file names with file extension, but without file path.
The error message output by DIR to handle STDERR if the specified directory does not exist at all or there is no file matching the pattern is suppressed by redirecting it with 2>nul to device NUL.
Read also the Microsoft documentation about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR captures everything written to STDOUT of started command process and processes the captured output line by line.
FOR ignores by default all empty lines (do not occur here) and all lines starting with a semicolon. A file name could begin with a semicolon. For that reason option eol=| is used to redefine end of line character to vertical bar which a file name can't contain, see Microsoft documentation Naming Files, Paths, and Namespaces. In this case on using TTT*_* as wildcard pattern it is not possible that a file name starts with a semicolon, but it would be possible on usage of *_* as wildcard pattern.
FOR would split up also each line into substrings (tokens) using space/tab as delimiters and would assign just the first space/tab separated string to specified loop variable A. This splitting behavior is not wanted here as file names can contain one or more space characters. Therefore the option delims= is used to define an empty list of delimiters which disables line splitting completely and results in assigning entire file name with extension to loop variable A.
The inner FOR processes just the file name (without extension) as string. This time the file name is split up using the underscore as delimiter because of delims=_ with assigning just first underscore delimited string to loop variable B because of tokens=1. Well, tokens=1 is the default on using for /F and so this option string could be removed from code.
So the outer FOR assigns to A for example TTTxy_test & example!.txt and the inner FOR processes TTTxy_test & example! and assigns to B the string TTTxy.
The command MD creates in set destination directory a subdirectory for example with name TTTxy. An error message is output also on directory already existing. This error message is suppressed by redirecting it to device NUL.
Then the file is moved from source to perhaps just created subdirectory in destination directory with overwriting an existing file with same name in target directory of the file.
The inner FOR loop could be optimized away when there are never files starting with an underscore or which have more than one underscore after first part of file name up to first underscore.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
md "%DestDir%\%%A" 2>nul
move /Y "%SourceDir%\%%A_%%B" "%DestDir%\%%A\"
)
endlocal
Option tokens=1* results in assigning first underscore delimited part of file name to loop variable A and rest of file name to next loop variable B according to ASCII table without further splitting up on underscores.
But please take into account that the optimized version does not work for file names like
_TTTxy_test & example!.txt ... underscore at beginning (ignored by pattern), or
TTTxy__test & example!.txt ... more than one underscore after first part.
The optimized version can be further optimized to a single command line:
#for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "C:\Development\test\TTT*_*" 2^>nul') do #md "C:\Development\test\%%A" 2>nul & move /Y "C:\Development\test\%%A_%%B" "C:\Development\test\%%A\"
Well, the not optimized version could be also written as even longer single command line:
#for /F "eol=| delims=" %%A in ('dir /B /A-D-H "C:\Development\test\TTT*_*" 2^>nul') do #for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do #md "C:\Development\test\%%B" 2>nul & move /Y "C:\Development\test\%%A" "C:\Development\test\%%B\"
See also Single line with multiple commands using Windows batch file for an explanation of operator &.
For additionally removing TTT from file name on moving the file the first batch code is modified with using two additional commands SET and CALL:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do (
md "%DestDir%\%%B" 2>nul
set "FileName=%%A"
call move /Y "%SourceDir%\%%A" "%DestDir%\%%B\%%FileName:~3%%"
)
)
endlocal
The file name is assigned to an environment variable FileName. The value of this environment variable cannot be referenced with just using %FileName% because of all references of environment variable values using percent signs are substituted by Windows command processor in entire command block starting with first ( and ending with matching ) before FOR is executed at all. Delayed expansion is usually used in such cases, but that would result here in file names containing one or more exclamation marks would not be corrected processed by the batch file.
The solution is using %% on both sides of FileName environment variable reference instead of % and force a double parsing of the command line by using command CALL.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
for /?
md /?
move /?
set /?
setlocal /?
It is really very simple:
#echo off
for /f "tokens=1-2 delims=_" %%i in ('dir /b /a-d "TTT*_*"') do (
if not exist "%%i" mkdir "%%i"
move "%%i_%%j" "%%i\%%j"
)
We split by _ into 2 tokens, %%i everything before _ and %%j everything after.
We simply create folder (if it does not exist) then move the file with only the name after the _ into the new folder.
So as an example file TTT123_File1.txt will create a folder called TTT123 and place the file into it but rename it as File1.txt
You might consider using Tcl/Tk. Tcl/Tk is an open source script language. You can call it as a stand-alone or execute it from a windows batch file. You will need to install it first if you don't have it yet.
The following Tcl script does what you want:
cd "C:/Development/test"
# glob is a tcl command to list all functions that match the requirements
set files [glob TTT*_*]
foreach f $files {
# use the underscore as a separator to split f and store the parts in dir and fnew
lassign [split $f "_"] dir fnew
if {![file exist $dir]} {
file mkdir $dir
}
file rename $f [file join $dir $fnew]
}
In my opinion, this is a very readable script, even if you don't know tcl.
You can call this script from a batch file as:
tclsh script.tcl
if you have saved the script as script.tcl

Getting a Windows batch file to rename a text file based on contents with wildcard matching

I have the following batch file which renames a text file by appending an underscore and characters from the contents of the file to the file name.
The contents are 5 characters from the first line in the file from position 56.
I can get this to work for a single file (1.spl) in my example, but I can't work out how to get this to run for all *.spl files in a folder.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
for /F "delims=" %%i in (1.spl) do (
set Z=%%i
goto BREAK1
)
:BREAK1
SET Z=%Z:~56,5%
RENAME 1.spl 1_%Z%.spl
You could use another FOR loop which calls for each *.spl file a subroutine for renaming the file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%# in ('dir *.spl /A-D /B 2^>nul') do call :RenameFile "%%#"
endlocal
goto :EOF
:RenameFile
for /F "usebackq delims=" %%I in (%1) do set "FirstLine=%%I" & goto GetNamePart
:GetNamePart
set "NamePart=%FirstLine:~56,5%"
if not exist "%~n1_%NamePart%%~x1" ren %1 "%~n1_%NamePart%%~x1"
goto :EOF
The FOR loop in main code - third line - uses command DIR to get a list of *.spl files before starting the rename operations. It is not advisable to use here just for %%# in (*.spl) do ... as the files in the current directory are renamed which means the directory entries change while FOR loop is running. It is strongly recommended to get first the complete list of *.spl files using DIR and then process this list independent on the file renames made in the directory.
The main FOR calls the subroutine RenameFile to process each file from the list.
A file is not renamed if there is already an existing file with same name. This is very unlikely but should be nevertheless checked first.
Please note that the batch code as is does not prevent for appending an underscore and the five characters from first line multiple times to a file name if the batch file is executed more than once on the directory. An additional IF condition would be needed to avoid multiple renames of files.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
ren /?
set /?
setlocal /?
The operator & as used on FOR loop in subroutine makes it possible to run multiple commands on a single command line, see Single line with multiple commands using Windows batch file for details.

Change extension of files in windows batch

I am trying to rename a lot of files. I only want to change the extention from ".pdf.OCR.pdf" to ".pdf"
So far I got the following code
rem for /r myPDFfolder %%i in (*.pdf.OCR.pdf) do ren "%%i" "%%~ni.pdf"
But it does not appear to work with the extension that has multiple dots -- what am I doing wrong?
Extension is the part of file name after the last dot.
Use string replacement to strip the unneeded part:
setlocal enableDelayedExpansion
for /f "eol=* delims=" %%i in ('dir /s /b "r:\*.pdf.OCR.pdf"') do (
set "name=%%~nxi"
ren "%%i" "!name:.pdf.OCR=!"
)
P.S. Parsing of dir is used to make the code more robust in case a different text is stripped which might have changed the sorting order and cause for to process the file twice or more times.
There is no need for a batch file. A moderate length one liner from the command prompt can do the trick.
If you know for a fact that all files that match *.pdf.ocr.pdf have this exact case: .pdf.OCR.pdf, then you can use the following from the command line:
for /r "myPDFfolder" %F in (.) do #ren "%F\*.pdf.ocr.pdf" *O&ren "%F\*.pdf.o" *f
The first rename removes the trailing .pdf, and the second removes the .OCR. The above works because *O in the target mask preserves everything in the original file name through the last occurrence of upper-case O, and *f preserves through the last occurrence of lower-case f. Note that the characters in the source mask are not case sensitive. You can read more about how this works at How does the Windows RENAME command interpret wildcards?
If the case of .pdf.ocr.pdf can vary, then the above will fail miserably. But there is still a one liner that works from the command line:
for /r "myPDFfolder" %F in (*.pdf.ocr.pdf) do #for %G in ("%~nF") do #ren "%F" "%~nG"
%~nF lops off the last .pdf, and %~nG lops off the .OCR, which leaves the desired extension of .pdf.
You should not have to worry about a file being renamed twice because the result after the rename will not match *.pdf.ocr.pdf unless the original file looked like *.pdf.ocr.pdf.ocr.pdf.
If you think you might want to frequently rename files with complex patterns in the future, then you should look into JREN.BAT - a regular expression renaming utility. It is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward. Full documentation is embedded within the script.
Assuming JREPL.BAT is in a folder that is listed within your PATH, then the following simple command will work from the command line, only renaming files that match the case in the search string:
jren "(\.pdf)\.OCR\.pdf$" $1 /s /p "myPDFfolder"
If you want to ignore case when matching, but want to force the extension to be lower case, then:
jren "\.pdf\.ocr\.pdf$" ".pdf" /i /s /p "myPDFfolder"
Alternative solution, without delayed expansion (remove ECHO to actually rename any files):
#echo off
rem iterate over all matching files:
for /F "delims=" %%A in (
'dir /S /B /A:-D "myPDFfolder\*.pdf.OCR.pdf"'
) do (
rem "%%~nA" removes last ".pdf"
for /F %%B in ("%%~nA") do (
rem "%%~nB" removes ".OCR" part
for /F %%C in ("%%~nB") do (
rem "%%~nC" removes remaining ".pdf"
ECHO ren "%%~fA" "%%~nC.pdf"
) & rem next %%C
) & rem next %%B
) & rem next %%A
NOTE: The directory tree is enumerated before for iterates through it because otherwise, some items might be skipped or tried to be renamed twice (see this post concerning that issue).

using the command line how can i modify filenames

how can i modify filenames in a folder based on delimiters in the filename?
I have a folder with images that get picked up by a different program based on a schedule- the program can only analyze the images if it contains just the main name (sku#) not the additional data that the photographers add after the name
using the command line can i run some sort of script to modify the filenames & delete all characters from after an underscore or hyphen (also need to delete underscore or hyphen)
(i dont know if & how its possible to do this thru the windows command line but i do have the option of running such a 'script' in cygwin- I prefer to use whatever works best...)
I haven't had a need to do this: but with a quick search I found this link on another Stack Exchange site.
A few people uploaded some powershell scripts. The top answer is a GUI tool to do mass name-changes.
There is this CMD example:
dir /B > fileList.txt
for /f "tokens=1,2,3" %i in (fileList.txt) DO ren "%i %j %l" %l
The first line outputs the list of files into a file called fileList.txt. The second line separates each of the names in the list into 3 parts, the #, the "-" and the rest of the name. For each of those it does the rename command.
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%a IN ('dir /b /a-d ^|findstr "_ -"') DO (
FOR /f "delims=_-" %%i IN ("%%a") DO ECHO REN "%%a" "%%i%%~xa" 2>nul
)
FOR /f "delims=" %%a IN ('dir /b /a-d ^|findstr "_ -"') DO ECHO failed ON "%%a"
This should do the job.
First step is to perform a directory listing in /b basic form (without headers - names only) and /a-d without directory names. This is filtered by findstr on (either underscore or dash) and %%a acquires each filtered filename in turn.
The next step is to take those filenames and split them into the parts on either _ or -. The first token (up to, but not including the delimiter) is applied to %%i, so the rename required is from "%%a" (the original filename) to "%%i%%~xa" - the first token+the extension from the original filename.
It's quite possible that the attempt to rename will fail because the new name already exists, so the error message is simply ignored (2>nul)
Finally, look for any un-renamed files and report them (optional, of course)
Note that the REName command is merely ECHOed. This ensures nothing is actually changed while you verify this is what you want to do. Simply remove the ECHO before the REN to activate the rename.

Resources