denmarks said:
I have a problem that resembles this. I would like to rename files in the
format
"nn song title.mp3" to "nnn song title.mp3" where the length of "nnn song
title" is not greater than 30 characters and nnn remains in the same sequence
as nn. Is there a program somewhere that can handle multiply forms of
renaming and renumbering?
Microsoft's implementation of wilcards really sucks. It isn't as good as glob constructs or gives you an eval to use regular expressions to compile a command or handle [sub]strings. I tried lots of ways to prefix new characters before the wildcards but it didn't work. It was like the wildcarded substring maintained its parsed length. I tried the following but they all screwed up:
filename: "5 test"
command: ren "? *" "00? *"
result: "00t est" (failed)
filename: "5 test"
command: ren "? test" "00? test"
result: "00t test" (failed)
filename: "5 test"
command: ren "? test" "?xx test"
result: "5xx test" (worked)
So Microsoft's wildcards won't let you prefix characters before the wildcard position and apparently retains the length of the substring that it parsed out. I can postfix after the wildcarded position just fine but that won't help you.
I don't know of a program that does what you want but below is a batch file that I whipped up that should work for you. Read the remark lines so you know what peculiarities might occur. This was a quick write so I probably did not account for every conceivable method that you might use for naming files with or without numeric prefixes (and conflicts will occur if they don't have a numeric prefix since zero will get used and could end up trying to rename to an already existing name).
In my case, I called the batch file "padprefix.bat". Just be sure to run it using:
cd <drive>:
cd <directory>
cmd /v /c <path>padprefix
You need to move to wherever are the files since the batch file only changes the names of files in the current directory (you might have to also change the current drive). The /v switch is mandatory to force immediate expansion of environment variables within for-loops. I put the batch file in the D:\Batch directory which is listed in my PATH environment variable so I don't need to specify the <path> to it.
I didn't bother with adding anything to truncate the resultant filename to 30 characters. That's a requirement for you but not for me, and I wasn't going to waste more time on this. My guess is that you'll need to use:
for %%a in (*) do (
set origname=%%a
set newname=!origname:~0,30!
echo "!origname!" renamed to "!newname!"
ren "!origname!" "!newname!"
)
in a batch file (ran under "cmd /v") to use only the first 30 characters of the filename in a rename command.
Below is the content of the batch file that I created (after the delimiter line below).
File: padprefix.bat
--------------------
echo off
cls
echo Execute: "%0"
echo.
echo Purpose: Convert numeric prefix in filename to zero-prefixed value.
echo Works only on files in current directory.
echo.
echo Syntax: %0 [length [test]]
echo where, length = How many digits in prefix number, zero padded on left.
echo test = Simulates renaming but no files get renamed.
rem -- ENVIRONMENT CHECK
rem - WARN: You must be running under 'cmd /v' to force immediate expansion of
rem - environment variables, especially needed inside for-loops. To run, enter:
rem - cmd /v /c <thisfile>.bat
REM -- Check "cmd /v" was used to enable delayed environment variable expansion.
set testvar=on
set chkvar=!testvar!
set testvar=
if NOT "%chkvar%" == "on" (
echo.
echo **ERROR** Delayed environment variable expansion is not enabled.
echo Use: "cmd /v" to load shell in which this batch file executes.
echo or: "cmd /v /c %0 [args]" to run this batch file directly.
echo.
set chkvar=
goto :EOF
)
rem --- PARAMETER(S)
rem - Length of numeric prefix (default = 3).
set numlength=%1
rem - Set to zero if not a number.
set /a numlength=numlength*1
if "%numlength%" == "0" set numlength=3
echo NOTE: Numeric prefix will be %numlength% digits long for this execute.
rem - If simulating, do not rename the files.
set simulate=off
rem - Use only first 4 characters of second argument.
set arg2=%2
set arg2=%arg2:~0,4%
if "%arg2%" == "test" set simulate=on
if "%arg2%" == "TEST" set simulate=on
set arg2=
if "%simulate%" == "on" echo ** (SIMULATION ONLY) **
echo.
rem - Clear arg in case user just hits enter (doesn't change current value).
set arg=
rem - Anything but "y" or "Y" will abort (only first character used).
set /p arg="Continue (y/N)? "
if "%arg:~0,1%" == "y" goto Continue
if "%arg:~0,1%" == "Y" goto Continue
echo -- ABORTED --
echo.
set arg=
goto :EOF
:Continue
set arg=
echo.
if "%simulate%" == "on" (
echo Simulating the rename ...
) else (
echo Renaming ...
)
echo.
rem --- MAIN
rem - NOTE: The 'set /a' is a trick to extract the leading number in a string.
rem - Returns zero if the string begins with a non-numeric character.
rem - WARN: The 'set /a' command will return zero for an illegal octal number,
rem - like 09 or 099. A leading zero means an octal value so it can only have
rem - digits 0 to 7. There is no way to disable the octal handling of the
rem - 'set /a' command, so LeftTrim is used to delete leading zeroes.
for %%a in (*) do (
set origname=%%a
set modname=!origname!
rem - Avoid 'set /a' octal conversion due to leading zero in string.
call :LeftTrim 0
rem - Get just the numeric prefix portion (return zero if none).
set /a numprefix=modname*1
rem - Pad out number prefix to ensure a minimum of numlength digits.
for /l %%b in (1,1,%numlength%) do set numprefix=0!numprefix!
rem - Use only last numlength digits.
set numprefix=!numprefix:~-%numlength%!
for /f "tokens=1,2*" %%i in ("!numprefix! !origname!") do (
if [%%k] == [] (
set newname=%%i %%j
) else (
set newname=%%i %%k
)
echo Old name = "!origname!"
echo New name = "!newname!"
if ["!origname!"] == ["!newname!"] (
echo [same name - rename skipped]
) else (
if exist "!newname!" (
echo [new name already exists - rename skipped]
) else (
if not "%simulate%" == "on" ren "!origname!" "!newname!"
)
)
echo.
)
)
if "%simulate%" == "on" (
echo -- SIMULATION DONE --
) else (
echo -- DONE --
)
echo.
set modname=
set newname=
set numprefix=
set numlength=
set simulate=
goto :EOF
rem --- FUNCTIONS
:LeftTrim
rem - Deletes specified leading prefix character(s), plus any leading space(s)
rem - after the delete. If prefix character omitted, delete leading spaces.
rem - Syntax: call :LeftTrim [char]
rem (uses global variable "modname")
if "%1" == "" goto DelSpace
rem - Use only the first character of the input parameter.
set delchar=%1
set delchar=!delchar:~0,1!
rem - Remove the prefix character(s).

elPrefix
if "!modname:~0,1!" == "!delchar!" (
set modname=!modname:~1!
goto DelPrefix
)
rem - Remove any [resultant] leading spaces.

elSpace
if "!modname:~0,1!" == " " (
set modname=!modname:~1!
goto DelSpace
)
set delchar=
goto :EOF
rem --- NOTES
rem - Some examples of renaming when numlength=3:
rem - "test.txt" --> "000 test.txt" (no number prefix will use zero)
rem - "4 test.txt" --> "004 test.txt"
rem - "09 thisfile" --> "009 thisfile"
rem - "28 test.txt" --> "028 test.txt"
rem - "137 test.txt" --> "137 test.txt" (no change effected)
rem - "12 this file" --> "012 this file"
rem - Some problems that could occur:
rem - "4026 test.txt" --> "026 test.txt" (only last 3 digits are kept)
rem - "42test.txt" --> "042 42test.txt" (no space delimiter was used)
rem - "46this file" --> "046 file.txt" ("46this" became "46" by 'set /a').
rem - If you see output like:
rem - Old name = "!origname!"
rem - New name = "!newname!"
rem - then you didn't use "cmd /v /c <thisfile>.bat" to run it.