How do I increment a folder name using Windows batch? - windows

I've got a batch script that creates a folder named New_Folder and a few subdirectories and files within. Currently, if I need to create multiple New_Folders I have to rename each New_Folder created by the batch before I can run it again and create a new one. What I'd like to do is have the batch check and see if New_Folder already exists, and if so, to increment New_Folder by a number. So I'd have New_Folder, New_Folder1, New_Folder2, and so on.
How would I go about doing this? The solutions I've seen for incrementing things in batch scripts don't seem to apply to my situation, and I don't know anything about batch scripting beyond what I've copy/pasted for my own code.

Here is a solution that will always work, even if there are gaps in the numbers. The folder number will always be 1 greater than the current max number.
#echo off
setlocal enableDelayedExpansion
set "baseName=New_Folder"
set "n=0"
for /f "delims=" %%F in (
'2^>nul dir /b /ad "%baseName%*."^|findstr /xri "%baseName%[0-9]*"'
) do (
set "name=%%F"
set "name=!name:*%baseName%=!"
if !name! gtr !n! set "n=!name!"
)
set /a n+=1
md "%baseName%%n%"

with that you will be able to count the number of occurence of "New_Folder*" and create one with the next number.
#echo off
set /a count=0
for /d %%d in (New_Folder*) do (
set /a count+=1
)
set /a count+=1
mkdir New_Folder%count%
Note that the best way would be to find the largest number at the end of New_Folder, but Windows Batch is very limitative and I'm a Linux guy!
EDIT : After about one hour of googling and testing :
#echo off
setlocal EnableDelayedExpansion
set max_number=0
for /d %%d in (New_Folder*) do (
set current_directory=%%~nxd
call:StrLength name_length !current_directory!
call:Substring directory_number,!current_directory!,10,!name_length!
if !directory_number! gtr !max_number! (
set max_number=!directory_number!
)
)
set /a max_number+=1
mkdir New_Folder%max_number%
:Substring
::Substring(retVal,string,startIndex,length)
:: extracts the substring from string starting at startIndex for the specified length
SET string=%2%
SET startIndex=%3%
SET length=%4%
if "%4" == "0" goto :noLength
CALL SET _substring=%%string:~%startIndex%,%length%%%
goto :substringResult
:noLength
CALL SET _substring=%%string:~%startIndex%%%
:substringResult
set "%~1=%_substring%"
GOTO :EOF
:StrLength
::StrLength(retVal,string)
::returns the length of the string specified in %2 and stores it in %1
set #=%2%
set length=0
:stringLengthLoop
if defined # (set #=%#:~1%&set /A length += 1&goto stringLengthLoop)
::echo the string is %length% characters long!
set "%~1=%length%"
GOTO :EOF
Note, the command line return me an error "The syntax of the command is incorrect." but everything works so I'll let you find why... New folder is created regardless of the order of directories or if they start at 1 or not :) Hope you'll enjoy!

This solution find the largest numbered name, and create the next one to it:
#echo off
for /d %%d in (New_Folder*) do set lastFolder=%%d
set /A nextFolder=%lastFolder:*New_Folder=% + 1
mkdir New_Folder%nextFolder%
EDIT: Previous solution doesn't correctly get the last numbered folder, but the next one is correct:
#echo off
setlocal EnableDelayedExpansion
set lastFolder=0
for /d %%d in (New_Folder*) do (
set folder=%%d
set folder=!folder:New_Folder=!
if not defined folder set folder=0
if !folder! gtr !lastFolder! set lastFolder=!folder!
)
set /A nextFolder=lastFolder+1
mkdir New_folder%nextFolder%

Related

Second latest folder in a Directory

I want a batch file which will find out which is the second latest folder created/modified in a directory.
I found this article but no matter how much i tried i could not understand how it works
#echo off
set "root_dir=c:\somewhere"
pushd "%root_dir%"
set "bl1="
set "bl2="
setlocal enableDelayedExpansion
for /f "tokens=* delims=" %%# in ('dir /b /a:-d /o:d') do (
set "bl2=!bl1!"
set "bl1=%%#"
)
echo %bl2%
endlocal
If i use it as it is then i can get the second latest folder but this script is supposedly able to get which ever latest folder you need , be it 1st or nth.
Could someone please tell me what modifications need to be done to the script to accomplish that. Also how exactly this script works
In your approach, the latest folder is already available in variable bl1; add echo %bl1% at the end before endlocal to display it. Retrieving the nth folder is simply not possible in a flexible way with that script as you would need to define another variable (say bl3, bl4,..., bln) within the loop.
However, you could reverse the sort order of the output of the dir command by changing the /O option, so it returns the latest (most recent) item first. Then let an index number count the iterations of the loop, and if that index equals the predefined number n, store the currently iterated item:
#echo off
setlocal EnableDelayedExpansion
rem // Define N here to get Nth-latest folder:
set /A LATEST=2
set /A INDEX=0
for /F "eol=| delims=" %%# in ('dir /B /A:D /O:-D "C:\somewhere"') do (
set /A INDEX+=1
if !INDEX! EQU !LATEST! (
set "ITEM=%%#"
)
)
if defined ITEM echo %LATEST%th-latest folder: %ITEM%
endlocal
exit /B
Update
Here is a modified script with the following improvements:
Exclamation marks ! in folder names are no longer lost due to toggling delayed expansion;
the target directory can be provided as the first command line argument; if omitted, the current directory is used;
the number n can be given as the second command line argument; if omitted, the user is prompted for it (this addresses elzooilogico's comment); n defaults to 1 for empty input;
the display output is improved to avoid something weird like 1th-latest, 2th-latest and 3th-latest; instead, The latest, 2nd-latest and 3rd-latest is returned, respectively;
So this is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* define location path and folder pattern as 1st command line argument;
rem /* Define number N as 2nd command line argument to get Nth-latest folder. */
set "LATEST=%~2"
set /A LATEST+=0
if %LATEST% LEQ 0 (set /P LATEST="Enter N [1]: " & set /A LATEST+=0)
if %LATEST% LEQ 0 set /A LATEST=1
set /A INDEX=0
for /F "eol=| delims=" %%# in ('dir /B /A:D /O:-D "%~1"') do (
set /A INDEX+=1
setlocal EnableDelayedExpansion
if !INDEX! EQU !LATEST! (
endlocal
set "ITEM=%%#"
goto :SKIP & rem // break loop after having retrieved Nth-latest folder;
) else endlocal
)
:SKIP
setlocal EnableDelayedExpansion
if defined ITEM (
if %LATEST% EQU 1 (echo The latest file: !ITEM!) else (
if %LATEST% EQU 2 (echo 2nd-latest file: !ITEM!) else (
if %LATEST% EQU 3 (echo 3rd-latest file: !ITEM!) else (
echo %LATEST%th-latest file: !ITEM!)))
)
endlocal
endlocal
exit /B
To achieve a similar result as with the simple script on top of this answer, you need to call this script by the following command line, supposing it has been saved as Nth-latest.bat:
Nth-latest.bat "C:\somewhere" 2

Windows batch - nested variables and delayed expansion

newbie here who would appreciate some help. I'm trying to generate to generate random file names (i.e. for each file in the source directory, a different random alphanumeric figure should be generated)
The function that generates the random alphanumeric name works but when the value is returned to the main routine, it remains the same across all the files. Not sure where the problem is but I suspect it has something to do with delayed expansion.
#Echo Off
Setlocal EnableDelayedExpansion
dir "D:/Source" /b > List.txt
FOR /F %%i in (List.txt) DO (
CALL:Alpha Numb
echo !Numb!
md D:\Output\%%~ni
rar a -v50M -hpabc123 -m0 -ep "D:\Output\%%~ni\!Numb!.rar" "D:\Source\%%i"
)
goto:eof
:Alpha
Setlocal EnableDelayedExpansion
Set _RNDLength=40
Set _Alphanumeric=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
Set _Str=%_Alphanumeric%987654321
:_LenLoop
IF NOT "%_Str:~18%"=="" SET _Str=%_Str:~9%& SET /A _Len+=9& GOTO :_LenLoop
SET _tmp=%_Str:~9,1%
SET /A _Len=_Len+_tmp
Set _count=0
SET _RndAlphaNum=
:_loop
Set /a _count+=1
SET _RND=%Random%
Set /A _RND=_RND%%%_Len%
SET _RndAlphaNum=!_RndAlphaNum!!_Alphanumeric:~%_RND%,1!
If !_count! lss %_RNDLength% goto _loop
REM Echo %_RndAlphaNum%
ENDLOCAL & SET "%~1=%_RndAlphaNum%"
Exit /b

Batch File to list folders and allow user selection

I have searched and searched to find a solution to (what feels like) a unique problem. Many
answers here have been quite helpful and have gotten me a long way, but the last bit has me stumped.
My batch file needs to open an executable in a folder with a variable name
This folder may be in one of two directories
This is what I originally had and it works
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET DIR1="%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET DIR2=C:\Application\SRW\Profiles
IF NOT EXIST %DIR1% (
GOTO PROFILE_2
) ELSE (
GOTO PROFILE_1
)
:PROFILE_1
for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
set foldername=%%~nxA
)
SET DIR1=%DIR1:"=%
SET DIR=%DIR1%\%foldername%\app.exe
GOTO START_APP
:PROFILE_2
for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
set foldername=%%~nxA
)
SET DIR=%DIR2%\%foldername%\app.exe
GOTO START_APP
:START_APP
START "" /b "%DIR%"
:EOF
ENDLOCAL
EXIT
Then I was thrown a curveball when I discovered that some users may have multiple profiles in the variable profile folder and they need to be able to select which one to use for that given task. Now I have a variable profile folder and either one or multiple variable profiles within that folder.
I have found code to list the folder names and display them in the command window for selection.
#echo off
cls
setlocal EnableDelayedExpansion
set /a count=0
for /d %%d in (*) do (
set /a count+=1
#echo !count!. %%d
)
setlocal DisableDelayedExpansion
set /P selection="select folder number:"
I also found this routine which allows the user to select a file from a list then it is supposed to translate that file name into a variable.
Batch Script Programming -- How to allow a user to select a file by number from a list of files in a folder?
Unfortunately, I cannot get the example in the link to work as is and I have no idea how to make it work with folder names as the folder name example and the file name example are close but not close enough for me to understand what to do. And even if it somehow does manage to work, how then can I make such a routine work within the original code posted above?
In addition, I really don't want the user to be forced to make a folder selection if there is only one folder. If only one folder exists, it should be placed into the folder name variable automatically and nothing displays to the user at all.
Is what I'm trying to do even possible at all?
Any help is most appreciated.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
::
:: Set count-of-targets and application name
::
SET /a targets=0
SET appname=app.exe
SET "dots=..."
::
:: clear all "$" variables
::
FOR /f "delims==" %%i IN ('set $ 2^>nul') DO SET "%%i="
::
:: look for app.exe in (1) userprofile... (2) \application\srw...
::
SET dir1="%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET dir2="C:\Application\SRW\Profiles"
:: My testing - my directory names
SET dir1="c:\sourcedir"
SET dir2="C:\destdir\test dir"
FOR %%s IN (%dir1% %dir2%) DO (
FOR /f "delims=" %%i IN ('dir /s /b "%%~s\%appname%"') DO ( CALL :process "%%~dpi"
)
)
::
:: Now have TARGETS=#hits; $_n=full pathname; $n=directoryname
::
IF %targets%==1 SET mychoice=1&GOTO chosen
::
:: repeat a menu
::
:again
CLS
FOR /l %%i IN (1,1,%targets%) DO (
IF %%i lss 10 (ECHO(%%i%dots%%dots:~0,1%!$%%i!) ELSE (ECHO(%%i%dots%!$%%i!)
)
SET mychoice=
SET /p mychoice="Please choose 1..%targets% : "
IF NOT DEFINED $_%mychoice% GOTO again
:chosen
CALL SET application="%%$_%mychoice%%%%appname%"
ECHO START "" /b %application%
GOTO :EOF
::
:: Parameter is quoted-full-pathname
::
:process
SET /a targets+=1
SET $_%targets%=%~1
SET $=%~1
FOR %%n IN ("%$:~0,-1%") DO SET $%targets%=%%~nxn
GOTO :eof
From what you've said, this should work.
First steps are to set up. Set the number of targets found and the real application name and clear out any variablenames that start "$".
Next step is to specify the directories to use. I simply copied yours, then overrode those settings with settings to suit my machine - you'd need to delete those overriding lines, of course. Note that the names should be set quoted...
Next, scan from each of the directories for the application. Each time an instance is found, call :process passing the full -terminated pathname.
:process increments the count of targets found and sets the variable $_n to the full pathname passed (dequoted) It then sets $ to the dequoted-full-pathname and uses a syntax-trick to have FOR find the application's immediate directory. %$:~0,-1% is the full pathname minus the last character - the \ so the results looks like a filename. That "filename" is then assigned to $n
Once the directory-scans are finished, %targets% will contain the er, number of targets. If that's 1, then we have all we need - we can only select target number 1, so that's chosen for us.
Otherwise, clear the screen and display a number of lines - %targets% to be precise. The format isn...immediatedirname` and an extra dot is added if the number of targets is less than 10 so that a long list will line up nicely.
Then ask for a line number.
At this point, the only $_ variables that exist are $_1..$_%targets% so if $_%mychoice% exists, it must be a valid choice. If it's not defined, then repeat the question...
CALLing SET application="%%$_%mychoice%%%%appname%" first parses the command, then parses it again. After the first parse, the line becomes (if mychoice=3) SET application="%$_3%app.exe" so on the second occasion,application` is properly set to the full fulename of the application - and quoted.
There wasn't much point in my starting the app, since it doesn't exist, so I just echoed it.
Given the extended requirement:
You's probably be starting this from a shortcut. Suppose you run that shortcut minimised and insert after the SETLOCAL
SET "poweruser=%1"
Add, after
IF %targets%==1 SET mychoice=1&GOTO chosen
the line
IF NOT DEFINED poweruser START "%username% - poweruser" "%~dpnx0" poweruser&GOTO :EOF
And change the
GOTO :EOF
just prior to the label :process to
EXIT
So that if it wasn't run in poweruser mode (therefore poweruser is NOT defined) AND %targets% is NOT 1 (I'm presuming it won't be 0) Then this user hasn't been set as a poweruser in the shortcut, but does have more than one target, so the job is restarted in poweruser mode (ie. maximised.)
Note that it doesn't actually matter what the string is after the "~dpnx0" - so long as it's a string. I just used poweruser What it does is tell the batch that it's being run in a normal window, not minimised.
For powerusrs, you could if you like set the shortcut to normal window or maximised AND put a parameter in the command line after the batchname, which will marginally quicken the procedure. Leaving it without parameters and minimised would suit ALL users as it will auto-adjust if more than 1 target is found.
I have tried this. It worked for me.
I answered your question in two steps. In the first one I translated your original code into a more readable one. Here it is:
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET "DIR1=%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET DIR2=C:\Application\SRW\Profiles
IF NOT EXIST "%DIR1%" (
for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
SET DIR=%DIR2%\%%~nxA\app.exe
)
) ELSE (
for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
SET DIR=%DIR1%\%%~nxA\app.exe
)
)
START "" /b "%DIR%"
ENDLOCAL
EXIT
You should check first that previous code is equivalent to your original one.
In the second step I added the profile selection to the previous code:
#ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET "DIR1=%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET DIR2=C:\Application\SRW\Profiles
IF NOT EXIST "%DIR1%" (
for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
SET DIR=%DIR2%\%%~nxA\app.exe
)
) ELSE (
call :SelectProfile
)
START "" /b "%DIR%"
ENDLOCAL
EXIT
:SelectProfile
rem Get a list of folders in User Profile dir
set count=0
for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
set /A count+=1
SET DIR[!count!]=%DIR1%\%%~nxA
)
rem Initialize the selected profile
set select=1
if %count% equ 1 goto endSelection
rem Show the profiles menu
cls
echo Available profiles:
echo/
for /L %%i in (1,1,%count%) do echo %%i- !DIR[%%i]!
echo/
rem Let's the user to select the profile
:select
set select=1
set /P "select=Enter number of desired profile [first one]: "
if not defined DIR[!select!] goto select
:endSelection
SET DIR=!DIR[%select%]!\app.exe
exit /B
Please note that previous code fail if the user enter spaces in the answer. This detail may be fixed, if needed.

Count Var in Windows Batch

In my batch file I have the following variables:
set collection=collection1
set environment=oracleDev
set processChain1=-help,-startimport %environment% %collection%
As you can see, my process chain contains two strings that are separated with a ",".
Now I want to count the two strings (later it could be more then one string). I tried it with:
Set count=0
For %%j in (%%processChain1%%) Do Set /A count+=1
echo %count%
But there is the first mistake. It prints out 1 and not 2. Why?
After counting the strings I want to start an application with each parameter (string from the variable processChain1)
I try it with:
FOR /L %%G IN (1,1,%count%) DO (
FOR /F "tokens=%count% delims=," %%H IN ("%processChain1%") DO java -jar App.jar %%H
)
This cant work correct now because the counter is wrong because of the first mistake. But I think if I can solve the first problem, the second should work fine. Is this correct?
As far I can tell, right now, is counting 1 because there's only one string in that var, you are making the split later, but your token count is already set to 1....
You need to split the first string (delims=,) and then in the second part, work with each result.
EDITED:
Try this...
#echo off
set collection=collection1
set environment=oracleDev
set processChain1="-help" "-startimport %environment% %collection%"
Set count=0
For %%j in (%processChain1%) Do Set /A count+=1
echo.Total count: %count%
pause
As you can see, I change the var processChain1 structure to separate the values with a space (default delimeter) and put every var in quotes...
At least it works, and gives you the total count.
Only of course, If you can use it in this way.
Hope it helps.
Cheers.
If not.. take a look here, maybe it's help : separate tokens in batch file
Good luck
EDITED 2 (to match new information)
Batch file: Metalhead89.bat
#echo off
:: define the vars
set collection=collection1
set environment=oracleDev
:: concatenate the vars with ++
set processChain1=-help -startimport++%environment%++%collection%
:: Get the total count plus, run each token found
Set count=0
For %%j in (%processChain1%) do (
Set /A count+=1
set line=%%j
call :processToken
)
:: This will be printed out, at the end of the loop
echo Total token count: %count%
goto :eof
:processToken
for /f %%f in ("%line%") do (
:: set the command var with your exe file for each token found
set command=Running command: java -jar app.jar %%f
call :runTheCommand
)
goto :eof
:runTheCommand
:: now we replace the doble ++ in the var string with space, to treat them as options
set str=%command%
set str=%str:++= %
:: finally we do a echo of the command with the option included
echo %str%
goto :eof
Now, Call that file from command line and you will get:
Z:\>call Metalhead89.bat
Running command: java -jar app.jar -help
Running command: java -jar app.jar -startimport oracleDev collection1
Total token count: 2
Good luck buddy ;-)
Here I am going to present my solution but the solution of gmo is at least as good as mine.
#echo off
rem !!!!!!!!!!!!!!!!!!!!!
rem Set Parameter options
rem !!!!!!!!!!!!!!!!!!!!!
set collection=collection1
set environment=oracleDev
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem Set Modules As Parameters
rem Watch out: Each module + his options has to be in quotation marks
rem Options are separated by comma without whitespaces
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
set helpModul="-help"
set importModul="-startimport,%environment%,%collection%"
rem !!!!!!!!!!!!!!!!!!!!!!!
rem Configure Process Chain
rem !!!!!!!!!!!!!!!!!!!!!!!
set activeProcessChain=%helpModule%,%importModul%
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem Start Content Integration Testing Framework
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Set count=0
For %%j in (%activeProcessChain%) Do Set /A count+=1
FOR /L %%H IN (1,1,%COUNT%) DO (
call :loopThroughParams %%H
)
exit /b
:loopThroughParams
FOR /F "tokens=%1 delims=," %%I IN ("%activeProcessChain%") Do (
echo.
echo.
java -jar %nameOfApplication% %%~I
)
exit /b
:end

issues with enabledelayedexpansion for file renaming batch script

i am writing a batch script monotonic file renamer. basically, it makes the titles of all the files 1 2 3 4 .... and so on. i have since expanded it to be able to handle files of different types (txt, doc, flv, etc) but not everything is working out.
my main concern is i have broken the delayed expansion calls i was making before. now using !var1! is never expanded, or never recognized as a variable.
here is a verbosely commented version of my script
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET tempfile=temp.txt
SET exttemp=exttemp.txt
if [%1] == [] goto usage
::make sure your dont overwrite something useful
if EXIST %tempfile% (
ECHO Temp file already exists, are you sure you want to delete?
del /P %tempfile%
)
if EXIST %exttemp% (
ECHO EXT Temp file already exists, are you sure you want to delete?
del /P %exttemp%
)
::initialize
SET /a counter=0
SET type=
SET /a ender=%1
::write filenames to tempfile
DIR /B /ON > %tempfile%
::read lines one by one
for /f "usebackq delims=" %%a in (%tempfile%) do (
REM make sure we do not rename any of the working files
if NOT "%%a"=="renamer.bat" (
if NOT "%%a"=="temp.txt" (
if NOT "%%a"=="exttostr.bat" (
SET /a counter+=1
REM get file extension
exttostr %%a > %exttemp%
SET /P type= < %exttemp%
REM housekeeping
del /F %exttemp%
REM rename
ren %%a !counter!.!type!
ECHO Renamed "%%a" to "!counter!.!type!"
)))
REM exit when we have run enough
if "!counter!"=="!ender!" goto exit
)
goto exit
:usage
echo Usage: renamer NUMFILES
:exit
::final housekeeping
DEL temp.txt
the idea is i drop my two files, renamer.bat(this file) and exttostr.bat(helper to get the file extension) into the folder and run it, it will rename files sorted alphabetically from 1 to how ever many files i specify.
when i run the code, it never uses the variables marked for delayed expansion appropriately, always leaving them as "!varname!", so it renames the first file "!counter!.!type!" and throws errors for the rest because there is already a file in the directory with that name.
this brings me to a secondary issue. sorting the dir list alphabetically results in a poor handling of numbered files. for example the list:
"1 7 15 75 120"
is sorted:
"1 120 15 7 75"
i have not been able to find a way around this yet, only that it is indeed the intended result of the dir sort. the only workaround i have is padding numbers with enough zeroes in the front.
thanks in advance for any insight!
everything is sorted but the second problem. i think i have not spoken well. i have this issue when i take IN the directory file names, not when writing out. so they already need to be padded. i has hoping there was some other way to read the directory and have it be sorted appropriately.
the most promising thing i have found is here: http://www.dostips.com/DtCodeBatchFiles.php#Batch.SortTextWithNumbers
#ECHO OFF
if "%~1"=="/?" (
echo.Sorts text by handling first number in line as number not text
echo.
echo.%~n0 [n]
echo.
echo. n Specifies the character number, n, to
echo. begin each comparison. 3 indicates that
echo. each comparison should begin at the 3rd
echo. character in each line. Lines with fewer
echo. than n characters collate before other lines.
echo. By default comparisons start at the first
echo. character in each line.
echo.
echo.Description:
echo. 'abc10def3' is bigger than 'abc9def4' because
echo. first number in first string is 10
echo. first number in second string is 9
echo. whereas normal text compare returns
echo. 'abc10def3' smaller than 'abc9def4'
echo.
echo.Example:
echo. To sort a directory pipe the output of the dir
echo. command into %~n0 like this:
echo. dir /b^|%~n0
echo.
echo.Source: http://www.dostips.com
goto:EOF
)
if "%~1" NEQ "~" (
for /f "tokens=1,* delims=," %%a in ('"%~f0 ~ %*|sort"') do echo.%%b
goto:EOF
)
SETLOCAL ENABLEDELAYEDEXPANSION
set /a n=%~2+0
for /f "tokens=1,* delims=]" %%A in ('"find /n /v """') do (
set f=,%%B
(
set f0=!f:~0,%n%!
set f0=!f0:~1!
rem call call set f=,%%%%f:*%%f0%%=%%%%
set f=,!f:~%n%!
)
for /f "delims=1234567890" %%b in ("!f!") do (
set f1=%%b
set f1=!f1:~1!
call set f=0%%f:*%%b=%%
)
for /f "delims=abcdefghijklmnopqrstuwwxyzABCDEFGHIJKLMNOPQRSTUWWXYZ~`##$*_-+=:;',.?/\ " %%b in ("!f!") do (
set f2=00000000000000000000%%b
set f2=!f2:~-20!
call set f=%%f:*%%b=%%
)
echo.!f1!!f2!!f!,%%B
rem echo.-!f0!*!f1!*!f2!*!f!*%%a>&2
)
this code can sort the filenames with one number in them (i.e. video100.mov is fine, video100video10.mov would break it)
the issue i have is i think adding a call to this helper fn will break it again, so i will be trying to include this in my modified renamer.bat now. any help is appreciated.
Probably the batch for extracting the extension reset the local environment.
But, you don't need it. You may extract the extension with the ~x option. Something similar to this ....
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
echo ren %%~fa !counter!%%~xa
)
)
goto :eof
to include leading zeroes in the counter, so that the directory sorts correctly, replace the previous rename command with three lines
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !counter!%%~xa
So putting all pieces together, add the monotonicrename function you just created in the batch file that can be as simpler as...
#echo off
setlocal enabledelayedexpansion
call :monotonicrename %1
goto :eof
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !zcounter!%%~xa
)
)
goto :eof
I didn't experience any issues with delayed expansion, everything worked fine for me (except, of course, for the fact that I didn't have the exttostr.bat helper script.)
Anyway, there are several things that could be improved about your script:
You don't need to store the result of DIR into a file to read it afterwards. You can read the output directly in the FOR loop.
You don't need the helper batch script. The extension can be extracted from %%a by using the ~x modifier with the loop variable: %%~xa. You can read more about modifiers by issuing HELP FOR from the command prompt.
The renamer batch file's own name can be referenced in the script as %0. You can apply the ~n modifier where you only need to use the name without the extension. The combined modifier of ~nx will give you the name with the extension.
So, here's how your script might look like with the above issues addressed:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=0
SET type=
SET /A ender=%1
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter!%%~xa"
ECHO Renamed "%%~a" to "!counter!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: %~n0 NUMFILES
As for your secondary issue, it can be easily resolved like this:
Use something like 100000 as counter's initial value. (Use however many 0s you like, but possibly no more than nine.) Add the same value to ender as well.
When renaming files, instead of !counter! use the expression that removes the first character (the 1): !counter:~1! (in fact, this is not about removal, but about extracting a substring starting from the offset of 1, learn more about it with the HELP SET command).
Here's the modified version of the above script:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=1000
SET type=
SET /A ender=%1
SET /A ender+=counter
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter:~1!%%~xa"
ECHO Renamed "%%~a" to "!counter:~1!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: renamer NUMFILES
You can also see that I made some other enhancements, like making sure the file name is enclosed in double quotes, and using GOTO :EOF instead of GOTO exit (:EOF is a special pre-defined label that points at the end of the batch script so you don't need to define your own).

Resources