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"
exit /B
: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 exit /B
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.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
call /?
dir /?
echo /?
endlocal /?
exit /?
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.