Batch file - output csv to different folders - batch-file

everything in my code is working fine except the last part.
I am wanting to output each text file to the folder with the same name. It is outputing the three text files into the one folder PentahoOutputs. However I am wanting to output it as the following:
folder system2.object2.assets contains file system2.object2.assets
folder system3.object3.assets contains file system3.object3.assets
folder system4.object4.assets contains file system4.object4.assets
#echo off SetLocal EnableDelayedExpansion
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC = C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( SET subdirs=%%a
result=!subdirs:~71,7!
result2=!subdirs:~79,7!
set "concats=!result!!delims!!result2!!DELIMS!!COMMAND!!DELIMS!!EN!"
echo !concats!
echo !CONCATS! >>C:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\!result!!delims2!!result2!!delims2!!assets!.CSV
)
PAUSE>NUL
edit ********** below
changing the problem code to the following puts each of the three files in each of the three folders... however i want one file in each folder
for /d %%b in (C:\Users\usre.username\Documents\Training\BatchFiles\PentahoOutputs\*) DO ( echo !CONCATS! >>%%b\!result!!delims2!!result2!!delims2!!assets!.csv )

From your posted code - given aschipfl's change as noted (although you don't attempt to use direc)
Your posted code has been mangled in an attempt, I assume, to disguise usernames. It also appears that you've cut down the actual code to show only the relevant section. This is good and understandable (but your edit has a glaring typo in the code - which is why you should cut-and-paste as far as possible.)
So - the setlocal following the #echo off must be separated by a & command-concatenator or be (my preference) on a separate line.
Within your for ... %%a ... block, you've removed the required set keyword for result*.
The fixed values you've used for substringing don't suit the changes you've made to the pathname, so the result in result is (eg) "tem3.ob"
If a value does not change within a block (like delims) then it's probably best to use %delims% - result changes, so you'd use !result! not %result%. !delims! also works, of course - but using the delayed-expansion form primes the reader to believe it's going to vary. (opinion)
'tis best with a string assignment to use set "var=value" as the quotes ensure that stray trailing spaces are not included in the value assigned. You only ever need to have that happen once...
OK - here's a revision
#echo OFF
SetLocal
SET DELIMS=,
SET COMMAND=AddChange
SET EN=EN
SET ASSETS=Assets
SET DIREC=U:\Users\user.username\Documents\Training\BatchFiles\PentahoOutputs\
SET DELIMS2=.
FOR /D %%a IN (%direc%*) DO (
FOR /f "tokens=1,2,3 delims=." %%p IN ("%%~nxa") DO IF /i "%%r"=="%assets%" (
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN%
echo %%p%delims%%%q%DELIMS%%COMMAND%%DELIMS%%EN% >> %%a\%%~na.CSV
)
)
GOTO :EOF
Note that I've used U: for the test directory (it's a ramdrive on my machine)
Given the outer loop, %%a is assigned the full pathname to the directory.
Since you imply that your target directorynames are system2.object2.assets then %%~nxa (the Name and eXtension of %%a) conveniently holds this string. Parsing that using delims of . and selecting the first 3 tokens would assign system2 to %%p, object2 to %%q and assets to %%r This avoids the substringing problem and permits system and object to be any length - not just 7.
The if statement ensures that the main block for for...%%p is only executed for directories found which fit ..asset (/i makes the if case-insensitive)
The required line can then be constructed from the metavariables and constants, as can the destination filename, so the enabledelayedexpansion is not required.

Related

Batch rename to numeric names with leading zeroes

So I'm trying to write a batch that renames <randomname>.EPL to fbXYZ.EPL (XYZ - number with leading zeroes)
So something like bes_rush.EPL should turn into fb001.EPL and other files should get renamed too (fb002.EPL, fb003.EPL, etc.)
Here's what I have so far
setlocal ENABLEDELAYEDEXPANSION
set/a fileNum = 0
set fileNum=0000%fileNum%
set fileNum=%fileNum:~-3%
for %%f in (*.EPL) do (
ren %%~nf%%~xf fb!fileNum!%%~xf
set/a fileNum += 1
)
I can make it rename numerically and it actually works but I can't add the leading zeroes at all,
all my attempts lead to it renaming only one file and leaving the rest
The following would be my suggestion:
Please note however, that the example does not cater for any existing filenames in the directory which already match fb<num><num><num>.EPL, so those will also be renamed with possible new numbers too.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "SourceDir=."
Set "FileGlob=*.EPL"
Set "Prefix=fb"
Set "FileNum=1000"
For /F Delims^= %%G In ('(Set PATHEXT^=^) ^& "%SystemRoot%\System32\where.exe"
/F "%SourceDir%":"%FileGlob%" 2^> NUL') Do (Set /A FileNum += 1
SetLocal EnableDelayedExpansion & Ren %%G "%Prefix%!FileNum:~-3!%%~xG"
EndLocal)
Insert your required source directory between the = and closing " on line 3, (I've used . for the current directory, as per your example, but you can use an absolute or other relative path as needed).
Insert your required file glob prefix string between the = and closing " on line 4, (I've used *.EPL to match your example).
Insert your required file name prefix string between the = and closing " on line 5, (I've used fb to match your example).
I've used 1000 as your starting file number, because Set /A uses integers, and sees multiple concurrent 0's as just 0. Adding the 1 will prevent that, and will be omitted, when the varible expansion, uses just the last three characters. I also adjusted it so that the file numbering begins with fb001.EPL, to match your question parameters, (your code was beginning the sequence with fb000.EPL).
I've enabled delayed expansion within the loop, because it is required, when both modifying and using a variable within the same parenthesized code block. It shouldn't normally be enabled for the entire script, because filenames and strings containing ! characters can be affected, (those characters will be omitted).
I've also gone 'belt and braces' with the file selection, by using where.exe. This utility is not affected by Windows using 8.3 naming, which, whilst it may not be an issue with your provided example, will match exactly extensions .EPL, not those which begin with .EPL. Standard For loops, (which you used), and the more commonly used Dir command are both affected by 8.3 naming.
For additional robustness, I've used the full path to where.exe with the system environment variable %SystemRoot%, to prevent reliance on the %Path% variable which is often broken, by its incorrect or accidental end user modification.
As a direct resolution to your own code without modification to the majority of it:
setlocal ENABLEDELAYEDEXPANSION
set /a fileNum = 1
set fileNum=1000%fileNum%
for %%f in (*.EPL) do (
ren "%%f" fb!fileNum:~-3!%%~xf
set /a fileNum += 1
)
I must add however, that's because your example code is using a standard for loop, you may have issues. The problem is that a your loop will pass the first file through to the do portion whilst it is still parsing the others under the all encompassing * glob. This means that fb001.EPL will be put back into the list for parsing, and could be picked up again for processing another time, this could continue for other files too!
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files\t w o"
SET /a filenumber=1001
FOR /f "delims=" %%b IN ('dir /b /a-d "%sourcedir%\*.epl" ' ) DO (
SET "originalfilename=%%~nb"
SET "notnumber=Y"
rem do not rename files "fb999"
IF /i "!originalfilename:~0,2!!originalfilename:~5!" == "fb" IF "!originalfilename:~4!" neq "" CALL :isnum !originalfilename:~2,3!
IF defined notnumber (
CALL :nextvalidnum
IF NOT DEFINED filenumber ECHO Fail - no available fb999&GOTO :EOF
REN "%sourcedir%\%%b" "fb!filenumber:~-3!.epl"
)
)
GOTO :EOF
:: Determine whether %1 is purely numeric
:isnum
SET "notnumber=9%1"
FOR /l %%z IN (0,1,9) DO CALL SET "notnumber=%%notnumber:%%z=%%"
GOTO :eof
:: set filenumber to next valid fb(1)999 or empty if not available
:nextvalidnum
IF %filenumber% gtr 1999 SET "filenumber="&GOTO :EOF
IF EXIST "%sourcedir%\fb%filenumber:~-3%.epl" SET /a filenumber+=1&GOTO nextvalidnum
IF %filenumber% gtr 1999 SET "filenumber="
GOTO :eof
Setting filenumber to 1001 initially, with the expectation of using the last 4 characters as the new fb999 name.
Read each .epl name, process only those files not named fb999. This is accomplished by remembering that the first character in a string is "character 0";detecting the first 2 characters of the name are fb, there are no characters beyond the fifth, the fourth character in the filename exists and the three characters starting at character 2 are all numeric. The routine "isnum" sets notnumber to undefined if the value provided as %1 is all-numeric and defined otherwise.
If notnumber is defined, the filename is to be processed. Detect the next valid number by incrementing filenumber if the file fb+last 3 characters of "filenumber".epl exists. If filenumber exceeds 1999 then there are no available numbers. so clear filenumber and use it as a flag to show a message and exit.

Batch Script - Rename files, removing a variable prefix and suffix

I have several files in a folder with names like
"prefix (S-N 12RE3123) suffix.pdf"
I would like to rename them to just "12RE3123.pdf", removing the prefix and suffix. The issue is that both the prefix and suffix are of varying lengths/ characters, so I cannot just rename by removing the first/last xx characters, but have to use the only commonality where only the characters inside the parenthesis following "S-N" are those to be kept.
There is one special case where a few of the serial numbers are named as WD-12RE3123, and I need to remove the WD- as well. If I had to do it manually, there aren't a lot of them like that so it wouldn't be the end of the world, but having it automated would be nice. I thought of maybe doing an if statement after the removal of prefix/suffix to check if the first 3 characters match WD- then remove those if true, but I am not sure on the implementation.
I am still a novice in batch or vbscript, so I was wondering if this can be done in either of those. Batch has the method "REN" to rename files, but since the final name depends upon what the current name is I am not sure how to set up delimiters or how to approach this.
Any assistance would be greatly appreciated.
Here is a simple solution for your request. It relies on the following facts:
the prefix portion does not contain any parenthesis ( or ) on its own (suffix might though);
the serial number does not contain any parentheses ( or ) on its own;
there are no duplicate serial numbers, also with respect to removal of potentional WD- strings;
This is the code (after having tested the code on the files in your target folder, you need to remove the upper-case ECHO command to actually rename the files):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Set constants here:
set "LOCATION=.\test"
set "PATTERN=*.pdf"
set STRINGS="S-N " "WD-"
cd /D "%LOCATION%"
for /F "eol=| delims=" %%K in ('dir /B "%PATTERN%"') do (
for /F "eol=| tokens=2 delims=()" %%L in ("%%~nK") do (
set "NAME=%%L"
setlocal EnableDelayedExpansion
for %%J in (%STRINGS%) do (
if "!NAME!"=="%%~J!NAME:*%%~J=!" (
set "NAME=!NAME:*%%~J=!"
)
)
ECHO ren "%%~fK" "!NAME!%%~xK"
endlocal
)
)
endlocal
exit /B
How it works:
the first section specifies the folder location, the file pattern and the strings to remove (after having extracted the portion within ()); adapt the values to your needs;
there are several nested for loops; the outermost one simply iterates all the files matching the given pattern (it basically reads and parses the output of a dir command applied on the given files and loops through the returned items; opposed to a standard for loop, this for /F method ensures that the entire folder is read before the loop starts iterating, which is necessary when modifying the enumerated folder content like we do here by renaming files; see also this thread about that issue);
the next for /F loop extracts the file name portion of interest, that is everything between the first pair of parenthesis, and stores it in variable NAME; this loop iterates once only per file;
the is another for loop which walks though all items in the STRINGS variable;
the if clause checks whether the current item of STRINGS occurs at the very beginning of the NAME value; if so, it is removed, otherwise not; this is just a safety query because perhaps a serial number might also contain a given STRINGS item in the middle or at the end (for instance, 123-WD-45A);
at this point, the renaming is performed (after having removed ECHO, of course);
the toggling of delayed expansion is intended to avoid trouble with some special characters in the file names;
And here is another script that uses a more complex method for extracting the interesting parts of the file names. It relies on the following facts:
there occurs only a single substring (S-NSPACE in the file name
the serial number is followed by a );
the serial number does not contain any parentheses ( or ) on its own;
there are no duplicate serial numbers, also with respect to removal of potentional WD- strings;
The code looks like this:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Set constants here:
set "LOCATION=.\test"
set "PATTERN=*.pdf"
set "FILTER=(S-N [^()][^()]*)"
set "IDENTIFYER=S-N "
set STRINGS="WD-"
cd /D "%LOCATION%"
for /F "eol=| delims=" %%K in ('
dir /B "%PATTERN%" ^| findstr /I /R /C:"%FILTER%"
') do (
set "NAME=%%K"
setlocal EnableDelayedExpansion
set "NAME=!NAME:*(%IDENTIFYER%=!"
for /F "eol=| tokens=1 delims=)" %%L in ("!NAME!") do (
setlocal DisableDelayedExpansion
set "NAME=%%L"
setlocal EnableDelayedExpansion
for %%J in (%STRINGS%) do (
if "!NAME!"=="%%~J!NAME:*%%~J=!" (
set "NAME=!NAME:*%%~J=!"
)
)
ECHO ren "%%~fK" "!NAME!%%~xK"
endlocal
endlocal
)
endlocal
)
endlocal
exit /B
Basically, this script works similar to the above one, with a few deviations:
the first section specifies a file name filter and the serial number identifyer (S-N) in addition;
the dir command in the outermost for loop is piped into a findstr command to filter out files not containing (S-N and ) and a string (not containing (/)) in between already at the beginning;
the part (S-N and everything before is removed, the result is stored in NAME;
the next for /F loop extracts everything up to but not including the first ) from the NAME value, which constitutes the file name portion of interest; this loop iterates once only per file;
the is another for loop which walks though all items in the STRINGS variable, which does not contain the S-N portion here as this has already been removed before; the rest in this loop is the same as in the above script;
at this point, the renaming is performed (after having removed ECHO, of course);
#ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*(*)*.*" '
) DO (
FOR /f "tokens=1,2delims=()" %%c IN ("%%a") DO (
FOR /f "tokens=1-3delims=- " %%m IN ("%%d") DO (
IF "%%o"=="" (ECHO(REN "%sourcedir%\%%a" "%%n%%~xa"
) ELSE (
ECHO(REN "%sourcedir%\%%a" "%%o%%~xa"
)
)
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.
Apply each filename matching the mask "()." to %%a
Tokenise using ( and ) as delimiters so that the parenthesised portion is in %%d
Re-tokenise using - and as delimiters so that the required number is in %%o for S-N patterns and %%n for WD- pattern.
Show the rename line.
Note: this should work provided the prefix portion does not contain parentheses and the parenthesised portion is exactly as described.
Magoo and aschipfl both provided good pure batch solutions.
I find development of custom batch scripts for every complex renaming task to be tedious, which is why I wrote JREN.BAT - a regex find/replace renaming utility. JREN.BAT is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward. Full documentation is available from the command line via jren /?, or use jren /?? for paged help.
With JREN.BAT, the solution is as simple as (untested):
jren "^.*\((?:S-N (?:WD-)?)(.+?)\).*" "$1.jpg" /fm *.jpg
If I got the regex wrong, it can easily be fixed. You should probably add the /T option to run the command in test mode first, and then remove it when everything looks good.
If you put the command in a batch script, then you must use CALL JREN.

Modify variable within loop of batch script

I am moving files based on their names to preset folders. I don't want to make new folders. So files should only be moved if the corresponding folder is existing already.
The file names all follow the same pattern: 1234_123456_AA_***********.(doc/pdf)
I have the following script below which works:
#echo on
for /r %%f in (*.*) do (
echo processing "%%f"
for /f "tokens=1-3 delims=_" %%a in ("%%~nxf") do (
move "%%f" C:\Users\xxxxxxxxx\Desktop\MOVEFILES\%%a_%%b_%%c\
)
)
pause
But the issue I am running into is that some of the files names have a '0' place holder in loop variable %%b, for example 1234_0123456_AA. But this file name should be interpreted like 1234_123456_AA and I want this file moved into the appropriate folder.
I have written this:
#echo on
SETLOCAL ENABLEDELAYEDEXPANSION
for /r %%f in (*.*) do (
for /f "tokens=1-3 delims=_" %%a in ("%%~nxf") do (
set z=%%b%
echo !z:~-6!
move "%%f" C:\Users\xxxxxxxxx\Desktop\MOVEFILES\%%a_%%z_%%c\
)
)
pause
I get the echo to remove the '0' place holder, but need to get that back into %%b in the file path of where the file should be moved to.
What to modify in code to get the desired behavior?
Use the following code with the corrections of JosefZ applied and some additional improvements:
#echo off
setlocal EnableDelayedExpansion
for /R %%F in (*_*_*.*) do (
for /F "tokens=1-3 delims=_" %%A in ("%%~nxF") do (
set "MiddlePart=%%B"
set "MiddlePart=!MiddlePart:~-6!"
if exist "%USERPROFILE%\Desktop\MOVEFILES\%%A_!MiddlePart!_%%C\*" (
move /Y "%%F" "%USERPROFILE%\Desktop\MOVEFILES\%%A_!MiddlePart!_%%C"
)
)
)
endlocal
pause
The improvements on code are explained below in details.
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.
echo /?
endlocal /?
if /?
move /?
set /?
setlocal /?
1. Search pattern
The first improvement is the pattern used in first FOR as only files should be moved with at least 2 underscores in file name. This pattern is still not the best one, but good enough for this task.
2. Loop variable
It is better to use loop variables in upper case to avoid problems with the modifiers.
For example using as loop variable %%f and using inside the loop %%~f to use the string (must not be a file or folder name) of loop variable f without surrounding quotes, command processor exits batch processing with an error message because it expects one more letter, the loop variable as %%~f is interpreted as full name of file/folder of loop variable ?.
The loop variables and the modifiers are case sensitive. Therefore %%~F is interpreted by command processor as string of loop variable F without surrounding quotes and %%~fF as file/folder name with full path and extension of the file/folder of loop variable F.
Some other characters like # can be also used as loop variable.
3. Assigning value to environment variable with quotes
On assigning a string to an environment variable, it is always good to use
set "variable=text or other variable"
Using the quotes as shown here has the advantage that not visible spaces/tabs after last double quote are ignored by command processor.
But with using just
set variable=text or other variable
everything after first equal sign up to line termination is assigned to the variable including trailing spaces and tabs added perhaps by mistake on this line in the batch file. This is nearly never good and a common source of a batch execution problem which can be easily avoided by using quotes right.
Using the quotes as show below is also not good as in this case both double quotes are part of the text assigned to the variable (plus trailing spaces/tabs). This is sometimes useful, but is most often a coding mistake.
set variable="text or other variable"
4. Delayed expansion
Referencing a variable set or modified within a block defined with (...) requires delayed expansion if the current variable value should be used and not the value assigned to the variable above the block. Therefore using %%z was wrong in original code as variable z was not defined above first FOR loop and therefore was replaced always with nothing on execution of the loops.
5. Environment variable USERPROFILE
Running in a command prompt window set results in getting displayed all predefined environment variables for the current user account. There is the variable USERNAME, but also USERPROFILE containing path to the userĀ“s profile directory with the Desktop folder and other user account related folders. Using environment variable USERPROFILE makes the batch file less dependent on Windows version and language of Windows.
ATTENTION:
The first FOR runs because of /R recursive on current directory and all its subdirectories. As the inner FOR loop moves all found files in current directory tree to subdirectories of %USERPROFILE%\Desktop\MOVEFILES, the current directory should be never any directory of this path.

Batch - Recurse directories from a variable and expand results in another variable

I'm creating a simple production environment for work and in doing so need to set specific environment variables for specific projects in batch file.
Here's what i want to achieve:
1) Define a single environment variable which would define a list of directories
2) Recurse down each directory and add all leaf folders to a final environment variable.
[EDIT] After looking back at what i originally posted i was able to remove some redundancy. But the "The input line is too long." error occurs when %LINE% gets too long. Using the short path expansion does help but it can still error out. I'll look at how to break the echo to a temp file next as suggested.
Here's what i currently have:
#echo off
set RECURSE_THESE_DIRS=C:\Users\eric\Autodesk
set TMP_FILE=%CD%TMP_FILE.%RANDOM%.txt
setLocal EnableDelayedExpansion
for %%i in (%RECURSE_THESE_DIRS%) do (
if exist %%~si\NUL (
for /f "tokens=*" %%G in ('dir /b /s /a:d %%i') do set LIST=!LIST!;%%G
)
)
set LIST=%LIST:~1%
rem !!! AT THE ECHO LINE BELOW IF %LIST% IS TOO LONG, THIS SCRIPT FAILS
rem !!! WITH The input line is too long. ERROR :(
echo %LIST%>%TMP_FILE%
endlocal
for /F "delims=" %%G in (%TMP_FILE%) do set FINAL_VAR=%%G
del /F %TMP_FILE%
So by setting RECURSE_THESE_DIRS to directories i wish to parse, i end up with a %FINAL_VAR% which i can use to specify paths for proprietary software i use. Or i could use this script to append to %PATH%, etc...
This works for me but i would love suggestions to improve/streamline my script?
The root of your problem is that batch is limited to fit the variable name, contents and = into 8192 bytes, hence your directory-list simply isn't going to fit into one variable.
Personally, I'd just spit out a dir/s/b/a-d list to a tempfile and process that file with a for/f "delims=" - after all, you'd be likely to need to process your ;-separated envvar similarly in whatever process you are proposing to execute.
For instance, here's a test producing the same error - not using filenames at all
#ECHO OFF
SETLOCAL
SET "var=hello!1234"
SET var=%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%%var%
SET var=%var%%var%%var%%var%
SET count=8000
:loop
SET /a count +=1
ECHO %count%
SET var=%var%x
ECHO %var%
GOTO loop
GOTO :EOF
This should fail where count=8184.
Suggestions:
Use for /d /r to handle the recursion
Maybe i'm wrong, but in your script, you traverse the directory hierarchy, adding each directory to temp file which is then readed to concatenate its lines into a variable which is then writed to temp file, to be read again in another variable. If concatenation of directories fit into a variable, why not concatenate them without any temporary file?
If concatenation is in the limit of line length, as suggested by npocmaka, and if soported by end application, user short paths. Also, instead of adding the new values in the same instruction (not line) that contains the for loop, use a call to a subrutine with the new value passed to it, and then append the value. It's slower, but command lines executed will be shorter.

Determine filename length from a batch file

I need to work two things into a .bat file I am working on for a little project. First things first, I have to know if any filename contained into the same folder (recursively) I launch my .bat in is any longer than 100 characters. If so, I need to make it 92 characters long and keep the extensions.
For example, I have this filename:
IncrediblyLongFileNameIAmSorryForThisItLooksLikeSomeDamnSpamJesusIAintEvenCloseTo100yetalmostwaitforitYEAH.omg
The above filename is 110 characters. I need to keep the extension, therefore the program should rename the file as this:
IncrediblyLongFileNameIAmSorryForThisItLooksLikeSomeDamnSpamJesusIAintEvenCloseTo100yetalmos.omg
So far, my main problem is that I don't know how to work with filename strings in batch. I used this code:
#echo off & setlocal enableextensions
FOR /R %%i IN (*.*) DO (
ECHO %%~nxi
FOR /f "delims=:" %%a in ('
^(echo."%%~nxi"^& echo.^)^|findstr /o .'
) DO set lenght=%%a-5
echo The length of "%%~nxi" is %lenght%
)
endlocal & goto :EOF
But I can't SET inside a FOR, and it can't do basic math either (i.e. it can't do the -5 operation).
The second thing, which I believe should be easier once the first one is done, is simply to compare all the filenames in the folder (recursive, once again) and make sure no filenames are the same. If the program finds any filenames that are the same, the second occurrence should be renamed to add something like l1l at the end. (I can't use parentheses here, therefore I use two ls instead to cover the number.) The only thing you need to take care of is the file extensions, because I can't add anything after the file extensions, lest they become unusable.
Can anyone offer explanations for how to accomplish this? I would really like to be able to work this out myself, but I simply lack experience in batch programming.
#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
SET "tempfile=%temp%\##fn##.92"
ECHO ::>"%tempfile%"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
SET "fullname=%%a"
SET "name=%%~na"
SET "ext=%%~xa"
CALL :chgname
)
del "%tempfile%"
GOTO :EOF
:chgname
:: Proposed new name part - first 92 characters of existing name
:: also prepare for adding modifier
SET "newname=%name:~0,92%"
SET /a modifier=0
:modl
:: See whether this name has already been found
ECHO %newname%%ext%|FINDSTR /b /e /i /g:"%tempfile%" >NUL
IF ERRORLEVEL 1 GOTO makechange
:: existing name - modify it
SET "newname=%name:~0,92%#%modifier%#"
SET /a modifier+=1
GOTO modl
:makechange
IF "%name%" NEQ "%newname%" ECHO REN "%fullname%" "%newname%%ext%"
>>"%tempfile%" ECHO %newname%%ext%
GOTO :eof
Reasonably simple problem.
Get a directory-list in basic form (full-filename only) and apply the full filename, name part and extension part to appropriately-named variables.
Manipulate the filename to a new name consisting of the first 92 characters of the original name part. Anticipate the need to modify this new name by establishing a modifier to optionally be applied.
See whether the proposed new name already exists in the temporary file of NEW names already processed. If not found on that file, safe to rename (if required) and record name used.
If the filename has already been used, modify it to the original first 92+ "#anumber#", increment the modifier in anticipation and try again.
Only two comments required further - first, I used # rather than ! because ! has a special meaning to batch. Second, writing :: to the tempfile (the name of the tempfile is irrelevant - I chose one that's unlikely to exist...) means that findstr doesn't complain because the file is empty, but :: can't possibly be a real filename.
The /b /e /i options to findstr mean that the name echoed in must exactly match a line (matches both /b - begin and /e - end) but /i - case is irrelevant.

Resources