setlocal enabledelayedexpansion
set "sourcedir=c:\testso"
set "filename=%1"
:: clear any variables starting #
for /f "tokens=1delims==" %%e in ('set # 2^>nul') do set "%%e="
:: number of files
set /a #files=8
set /a #files1k=1000+#files
set "parm= %* "
set /a #count=0
set /a #randomadd=0
call :readparms %parm%
:: if 0 or 1 parameter, shuffle randomly
if %#count% lss 2 goto shuffle
:: unshuffling
echo unshuffling
call :shuffleren
goto :eof
:shuffle
set /a #remain=#files1k
for /L %%e in (1001,1,%#remain%) do set "#%%e="
:another
set /a #choice=((%random%+#randomadd) %% #files) + 1001
if defined #%#choice% goto another
if %#remain%%#choice%==10011001 goto shuffle
if %#choice% equ %#remain% goto another
set /a #%#choice%=%#remain%
if %#remain%==1001 goto doneshuffle
set /a #remain-=1
goto another
:doneshuffle
set "#report="
set #lastnum=0
for /L %%e in (1001,1,%#files1k%) do (
set /a #num=!#%%e!-1000
set /a #lastnum+=1
if !#num!==!#lastnum! goto shuffle
set /a #lastnum=#num
set "#report=!#report! !#num!
)
call :shuffleren
echo sequence=%#report:~1%
goto :eof
:shuffleren
for /L %%e in (1001,1,%#files1k%) do (
set "#oldname=%%e"
set "#newname=!#%%e!"
ren "%sourcedir%\%filename%*.!#oldname:~-3!" "%filename%*.!#oldname:~-3!.!#newname:~-3!.t"
)
for %%b in ("%sourcedir%\%filename%*.t") do ren "%%b" "%%~nb"
goto :eof
:readparms
shift
set "parm=%1"
if not defined parm goto :eof
set "parm=9%1"
for /L %%e in (0,1,9) do set "parm=!parm:%%e=!"
if defined parm echo ignored "%1" &goto readparms
set /a #randomadd=%1
set /a parm=1000+%1
set /a #count+=1
set /a #count1k=1000+#count
set /a #%parm%=#count1k
goto readparms
We start with setting the directory to examine and read the filename from the parameter list; then clear any variables starting #.
Establish the number of files to manipulate - I've seen the revised spec. that this should be 49, not 50. I used 8 for testing.
Calculate 1000+#files to save repeatedly calculating. Initialise the count of numeric parameters found and read the parameters from the command line using :readparms. I had some control options to facilitate testing, so added a space either end of the passed parameters list %*.
Having read and stored the parameters,examine #count - 0 or 1 means to shuffle, more means unshuffle.
So, shuffling :
First, set all variables #1001 to #1050 (it's self-adjusting to #files specified) to nothing.
Next, generate a random number 1001..1050 and if it's not already assigned, assign the remaining number from the range 1001..1050 to #the randomnumber and decrement the number remaining until it reaches 1001 (last one assigned). If both #count and #remain are 1001 then we're attempting to rename .001 to .001 so we start again. If #remain and #choice are the same otherwise, choose another number
When we're done shuffling, we need to build the unshuffle string. We grab each number in turn from #1000 to #1050, convert it to a natural number (no leading zeroes) and compare it against the last number processed - if the difference is 1, then we're attempting to resequence 2 sequential filenumbers, and that's not allowed - so restart the shuffling.
Finally, we have a set of variables such as
#1001=1004
#1002=1003
#1003=1002
#1004=1001
which means that file.001 will become .004 ,etc.
So, execute :shuffleren to rename the files.
I chose to rename the files by appending an extra 2 extensions (the new name and a t) then remove the t. This shows a trace of the old and new names (filename.002 becomes filename.002.003 in the above). Changing "%filename%*.!#oldname:~-3!.!#newname:~-3!.t" to "%filename%*.!#newname:~-3!.t"would change filename.002 to filename.003.
Finally, the unshuffle mechanism relies on a string of space-separated numeric arguments that matches the list printed by the shuffle mechanism. It's reaaly just more of the same, but unchecked so providing duplicate or insufficient numbers will no doubt cause a mess. Build a table like the above from the parameters and call the
:shuffleren routine to change the numbers back.
Of course, you should test the routine in a dummy area - don't apply it directly to live files.
Since the random function is seeded from the time, I've attempted to apply some variability by adding into the number-choosing mechanism a number that may be specified on the command line, hence
0 or 1 numeric arguments - if one numeric argument is provided, that argument is added to the random number so you can have a little bit of variation if you happen to run the routine at the same time on two days.
---- revision
@echo off
setlocal enabledelayedexpansion
set "sourcedir=c:\testso"
set "filename=%1"
:: clear any variables starting #
for /f "tokens=1delims==" %%e in ('set # 2^>nul') do set "%%e="
:: number of files
set /a #files=50
set /a #files1k=1000+#files
:: length of code to generate
set /a #lencode=10
set "parm= %* "
set /a #count=0
set /a #randomadd=0
set /a #assigned=0
call :readparms %parm%
:: if 0 or 1 parameter, shuffle randomly
if %#count% gtr 2 goto extendkey
:shuffle
set "#shuffle=y"
for /L %%e in (1,1,%#files%) do set "#%%e="
set "#report="
set /a #assigned=0
: nextrandom
call :assignrandom
if %#assigned% lss %#lencode% goto nextrandom
set "#key=%#report%"
:: Extend the key currently in #Report
:extendkey
set /a #accum=1
:nextmore
call :addmore %#report%
if %#assigned% equ %#files% goto donerandom
if %#accum% neq 10 goto nextmore
:: attempt to assign all unassigned
for /L %%e in (%#files,-1,1) do (
set /a #choice=%%e-1
call :addreport
)
if %#assigned% neq %#files% if defined #shuffle goto shuffle
if %#assigned% neq %#files% echo Fail&goto :eof
:donerandom
if defined #shuffle echo key is %#key%
: now build rename-list
for /L %%e in (1000,1,%#files1k%) do set "#%%e="
set /a #position=1000
:brlloop
set /a #position+=1
set /a #value=%#report% 2>nul
set /a #value+=1000
if defined #shuffle (set /a #%#position%=#value
) else set /a #%#value%=#position
set "#report=%#report:* =%"
if defined #report goto brlloop
:shuffleren
for /L %%e in (1001,1,%#files1k%) do (
set "#oldname=%%e"
set "#newname=!#%%e!"
ren "%sourcedir%\%filename%*.!#oldname:~-3!" "%filename%*.!#oldname:~-3!.!#newname:~-3!.t"
)
for %%b in ("%sourcedir%\%filename%*.t") do ren "%%b" "%%~nb"
goto :eof
:readparms
shift
set "#choice=%1"
if not defined #choice goto :eof
set "#choice=9%1"
for /L %%e in (0,1,9) do set "#choice=!#choice:%%e=!"
if defined #choice echo ignored "%1" &goto readparms
set /a #randomadd=%1
set /a #count+=1
set /a #choice=%1-1
call :addreport
goto readparms
:: Assign a new random number to #report
:assignrandom
set /a #choice=%random%+#randomadd
:: Caution - flow-through
:: Add and count an entry into #report
:: don't add if #choice is already in #report or #assigned
:addreport
set /a #choice=(#choice %% #files) + 1
set /a #assigned+=1
for %%y in (%#assigned% %#report%) do if %#choice%==%%y set /a #assigned-=1&goto :eof
set "#report=%#report%%#choice% "
goto :eof
:: Add some more numbers derived from the existing list
:addmore
set /a #accum+=1
:movel
if "%1"=="" goto :eof
set /a #choice=0
for /L %%y in (1,1,%#accum%) do call set /a #choice=#choice+%%%%y 2>nul
call :addreport
shift
goto movel
This code limits the "key" to #lencode.
First step is to process the parameters provided, but this time build each parameter into #report (the name is a hangover from earlier processing)
If there are fewer than 2 parameters provided, then this is a suffle operation and #shuffle is set. In this case, #lencode random numbers are added to a new #report. If #shuffle is not set, then the key has been provided in the command line and has been assigned to #report.
Using #report as a basis, a specific function is applied, adding new numbers. This means that the result in #report will be identical for the two cases (shuffling or unshuffling) All that is needed then is to add 1000 to the numbers for substringing purposes and build the #1xxx array; either for shuffling or unshuffling; then run the renaming code as before.
If an incorrect code is supplied, then the unshuffling will cause chaos. The file renaming trace-for-verification system survives from the earlier code.
-- another revision
@echo off
setlocal enabledelayedexpansion
set "sourcedir=c:\testso"
set "filename=%1"
:: clear any variables starting #
for /f "tokens=1delims==" %%e in ('set # 2^>nul') do set "%%e="
:: number of files
set /a #files=50
set /a #files1k=1000+#files
:: length of code to generate
set /a #lencode=10
set "parm= %* "
:: Set flag #shuffle
for %%e in (shuffle) do (
if "!parm!" neq "!parm:/%%e=!" set "#%%e=Y"&set "parm=!parm:/%%e=!"
)
set /a #count=0
set /a #randomadd=0
set /a #assigned=0
call :readparms %parm%
:: if 0 or 1 parameter, shuffle randomly
if %#count% gtr 2 goto extendkey
:shuffle
set "#shuffle=y"
for /L %%e in (1,1,%#files%) do set "#%%e="
set "#report="
set /a #assigned=0
: nextrandom
call :assignrandom
if %#assigned% lss %#lencode% goto nextrandom
set "#key=%#report%"
:: Extend the key currently in #Report
:extendkey
set /a #accum=1
:nextmore
call :addmore %#report%
if %#assigned% equ %#files% goto donerandom
if %#accum% neq 10 goto nextmore
:: attempt to assign all unassigned
for /L %%e in (%#files,-1,1) do (
set /a #choice=%%e-1
call :addreport
)
if %#assigned% neq %#files% if defined #shuffle goto shuffle
if %#assigned% neq %#files% echo Fail&goto :eof
:donerandom
if defined #shuffle if defined #key echo key is %#key%
: now build rename-list
for /L %%e in (1000,1,%#files1k%) do set "#%%e="
set /a #position=1000
:brlloop
set /a #position+=1
set /a #value=%#report% 2>nul
set /a #value+=1000
if defined #shuffle (set /a #%#position%=#value
) else set /a #%#value%=#position
set "#report=%#report:* =%"
if defined #report goto brlloop
:shuffleren
for /L %%e in (1001,1,%#files1k%) do (
set "#oldname=%%e"
set "#newname=!#%%e!"
ren "%sourcedir%\%filename%*.!#oldname:~-3!" "%filename%*.!#oldname:~-3!.!#newname:~-3!.t"
)
for %%b in ("%sourcedir%\%filename%*.t") do ren "%%b" "%%~nb"
goto :eof
:readparms
shift
set "#choice=%1"
if not defined #choice goto :eof
set "#choice=9%1"
for /L %%e in (0,1,9) do set "#choice=!#choice:%%e=!"
if defined #choice echo ignored "%1" &goto readparms
set /a #randomadd=%1
set /a #count+=1
set /a #choice=%1-1
call :addreport
goto readparms
:: Assign a new random number to #report
:assignrandom
set /a #choice=%random%+#randomadd
:: Caution - flow-through
:: Add and count an entry into #report
:: don't add if #choice is already in #report or #assigned
:addreport
set /a #choice=(#choice %% #files) + 1
set /a #assigned+=1
for %%y in (%#assigned% %#report%) do if %#choice%==%%y set /a #assigned-=1&goto :eof
set "#report=%#report%%#choice% "
goto :eof
:: Add some more numbers derived from the existing list
:addmore
set /a #accum+=1
:movel
if "%1"=="" goto :eof
set /a #choice=0
for /L %%y in (1,1,%#accum%) do call set /a #choice=#choice+%%%%y 2>nul
call :addreport
shift
goto movel
This time, you need to add a switch /shuffle if you are providing a key and wish to shuffle. Without the /shuffle switch, specifying fewer than 2 numeric arguments will shuffle randomly, more than 2, unshuffle.
Note that #key will only be established for a random shuffle, so that is the only time it's reported (otherwise, the key was provided or it's unshuffling).