Trying use a batch file to delete filenames appended with numbers - batch-file

I"m trying to delete these files with numbers appended to them using a for loop in a Windows batch file.
My problem is that I can't seem to build the filename strings using the for loop, despite several attempts at doing this.
Below is the snippet of my code that I"m trying to run with. As you can see, I've got 4 files named file0.txt, file1.txt, file2.txt and file3.txt in some nested folder, and I'm trying to delete them using a for loop
Ideally I want to be able to be able to set the limit of the for loop depending on how many files there are. And then I'd want to change the file extension from .txt to whatever to delete other files except the ones I want to keep.
Any help would be appreciated!! Here's the code:
setlocal enabledelayedexpansion
set num=3
set /a forLoopLimit=%num%-1
cd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
setlocal enabledelayedexpansion
echo %x
set y=%x
set filename=file%y%.txt
del %filename% /f /q
echo %filename%
)
cd ..

setlocal enabledelayedexpansion
set num=3
set /a forLoopLimit=%num%-1
cd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
echo %%x
set filename=file%y%.txt
ECHO del file%%x /f /q
echo file%%x
)
cd ..
Problems:
To refer to the metavariable (Loop-control variable) x, you need %%x, not %x within a batch file.
setlocal is not a switch. Each time it is used, it establishes a new frame which is terminated by endlocal or reaching end-of-file.
If you are using delayededexpansion then you need to refer to the variable you are changing using !var!, not %var%. !var! means the changed value, %var% means the value of the variable as it was when the for keyword was encountered.
You don't need to use y in your application. %%x is actually a string, but it will be a numeric string, so it can be used in calculations.
The del command is simply echoed above to allow the command to be displayed - in case there's a code error which might delete unexpectedly.

Basically, you fell into the delayed expansion trap (you enabled delayed expansion, but you didn't use it).
But your task can be done without those variables that need delayed expansion. You can use %%x directly and define the rest outside the loop:
#echo off
set num=3
set /a forLoopLimit=%num%-1
set "filebase=file"
pushd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
ECHO del "%filebase%%%x.txt" /f /q
)
popd
Like Magoo, I disarmed the del command by just echoing it. If the output is what you expect, just remove the ECHO.

Related

How to find and replace part of filenames from list

I have a list of files that I need to rename at the same part of each file, with different values.
Example:
BL_1402B103_abc.wav > BL_C1234-1_abc.wav
BL_15489B59_abc.wav > BL_C1234-5_abc.wav
So in the first example above I want to replace the 1402B103 with C1234-1 all the files are the same length and the sections I want to replace are separated by "_".
I have some code for finding/replacing parts of a filename but I need to do this for hundreds of files - is there a way to pull Pattern= & Replace= as variables from a csv/list and run as a batch?
Setlocal enabledelayedexpansion
Set "Pattern=1402B103"
Set "Replace=C1234-1"
For %%f in (*.wav) Do (
Set "File=%%~f"
Ren "%%f" "!File:%Pattern%=%Replace%!"
)
You could create a csv file and add your search/replace strings:
myfile.csv
1402B103,C1234-1
15489B59,C1234-5
etc,etc
The batch file, myrename.cmd
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,* delims=," %%i in (myfile.csv) do (
set "search=%%i"
set "replace=%%j"
call :fix
)
exit /b
:fix
for %%a in (*!search!*.wav) do (
set "file=%%a"
set "file=!file:%search%=%replace%!!"
echo ren "%%~fa" "!file!"
)
It will seatch for each string in the csv file, split by comma assign the first meta variable to the search variable and the second to the replace variable. Then we simply do the replace for each by calling that procedure.
Note!! in this instance I used echo before ren for testing results. Only once you are happy with your results should you remove echo to perform the actual command.
I would do such a multi-rename operation of files using shareware Total Commander with its built-in multi-rename tool which has a every easy to use graphical user interface for such tasks making it possible to review the new names of the files before executing the rename operation. This file rename operation could be done with Total Commander nearly complete using only some mouse clicks, just C1234- need to be typed on keyboard. And Total Commander supports even an undo if the rename operation fails for some reason.
Let us assume C1234- in new file name is a fixed sequence of characters and 1 and 5 is a number incremented by one on each renamed each file.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FileNumber=1"
for /F "eol=| delims=" %%I in ('dir BL_????????_abc.wav /A-D-H /B /ON 2^>nul') do (
move /Y "%%I" "BL_C1234-!FileNumber!_abc%%~xI" >nul
set /A FileNumber+=1
)
endlocal
This solution works for the example.
But what about string left to first underscore and string right to second underscore vary from file name to file name?
In this case the following batch file could be the right solution:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FileNumber=1"
for /F "eol=| delims=" %%I in ('dir *_????????_*.wav /A-D-H /B /ON 2^>nul') do (
for /F "eol=| tokens=1,2* delims=_" %%A in ("%%~nxI") do (
move /Y "%%I" "%%A_C1234-!FileNumber!_%%C" >nul
)
set /A FileNumber+=1
)
endlocal
The command MOVE with option /Y is used instead of command REN to make the file rename even on a file with that name is already existing. Total Commander would inform the user about such an issue on renaming files with other files with new name already existing.
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.
dir /?
echo /?
endlocal /?
for /?
move /?
set /?
setlocal /?
Read the Microsoft article 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.
Batch solutions just make it hard to know what to do.
Batch is far too unreadable for my liking. %% and ! and !! in weird places. Bah.
You are better off making a C# console app that gives you 2 prompts and just does it, like I did.
In any case, what is being demonstrated is, for each file, you grab that filename as a string variable, and do all the string replacements in that string variable. Then you rename the file, or in C# it's MoveTo(newPath), the resulting string variable.

Batch, unattended args in for loop

I used to work with a batch that loop to a folder and all subfolder and move all files found in another place.
A made modifications to this batch and now, the main loop is not working anymore.
set "arg1=%~1"
setlocal enabledelayedexpansion
cd /d D:\!arg1!
set /a count=0
for /r %%i in (*.*) do (
...
)
Run
myBatch test
And got a %i was unattended
The strangest part is that I did not change this part of code
If you have a composed name as argument use doublequote in the CD:
set "arg1=%~1"
cd /d "D:\%arg1%"
setlocal enabledelayedexpansion
set /a count=0
for /r %%i in (*.*) do (
...
)
One thing I see that will cause a problem is if you pass the name of a folder that has ! in the folder name. Change
cd /d D:\!arg1!
to
cd /d D:\%arg1%
You don't need to delay expansion of that line because it is not in a FOR loop or a parenthesized block of code. In fact you do not need to setlocal enabledelayedexpansion at all for the code you have shown... of course it may be required for the code that is not shown.
Also, be sure to quote the argument (folder name) when you invoke the bat file in case there are spaces in the folder name.
If none of this fixes your problem, can we see more of the code? At least any sections of code that contain %%i

Renaming multiples files with .bat

I've been looking for a .bat file in Windows 7 that given a name and a file directory, renames all of the files in that directory to the name that the user pass concatenated to a number that goes from 0 to 9.
For example:
Let's say that i have a directory with two files a.txt and b.txt, i want to change their names to documentX.txt (X being a number from 0 to 9), so at the end the script will change the names to document1.txt and document2.txt
i have tried something like this but without sucess:
#echo off
#set a=1
#set pref=hola
for /D %%f in (C:\*.txt)
do
rename *.txt %pref%%a%
#set /A a = %a%+1
The FOR command cannot span multiple lines unless you use parentheses or line continuation ^. The first opening parenthesis must be on the same line as the IN and the 2nd on the same line as the DO.
You cannot use normal expansion within a parenthesised block of code that also sets the value because the expansion occurs at parse time and the entire block is parsed at once. So the value will be the value that existed before you set it! The solution is to use delayed expansion. That occurs when the line is executed. It must be enabled with setlocal enableDelayedExpansion.
Delayed expansion causes a problem because ! is valid within a file name and FOR variable expansion will be corrupted if it contains ! while delayed expansion is enabled. The solution is to toggle delayed expansion on and off within the loop.
You want a simple FOR without any options. The /D option looks for directories instead of files.
You do not need to expand numeric variables within a SET /A statement.
One last thing - no need for # after you use ECHO OFF.
#echo off
setlocal disableDelayedExpansion
set "n=0"
set "pref=document"
for %%F in (c:\*.txt) do (
set "file=%%F"
set /a n+=1
setlocal enableDelayedExpansion
ren "!file!" "%pref%!n!.txt"
endlocal
)
There is a simpler way to accomplish the task. Use DIR /B to list all the .txt files and pipe the results to FINSTDR /N "^". The FINDSTR will match all files and will prefix each value with a sequential number followed by a colon. Use FOR /F to parse the result into the number and the file name so you can then RENAME.
#echo off
setlocal
set "pref=document"
for /f "tokens=1* delims=:" %%A in ('dir /b /a-d *.txt^|findstr /n "^"') do (
ren "%%B" "%pref%%%A.txt"
)

use * with a batch file to get filenames

I am using Windows XP and need to create a batch file to move tok.filename to filename.tok.
This works for one file if I type in fix.bat tok.filename.
set filename=%1
set newname=%filename:~4,45%
ren %1 %newname%.tok
I need to type in fix.bat tok*, but this puts tok* in the filename.
How do I get it to read all the files into the filename one at a time?
Use a for statement.
setlocal enabledelayedexpansion
for %%i in (tok.*) do (
set filename=%%i
set newname=!filename:~4,45!
ren %%i !newname!.tok
)
Enabling the delayed expansion makes it so that the variables are evaluated at the time they are used.
Alternatively, since you already have a batch file that works, you could write another batch file that uses the for statement, which calls your working batch file -- like this:
for %%i in (tok.*) do call fix.bat %%i
Or you could run it directly from the command line like this:
for %i in (tok.*) do call fix.bat %i
No need for a batch script
for %F in (tok.*) do for /f "delims=." %X in ("%~xF") do ren "%F" "%X.%~nF"
Double up the percents if used within a batch script.
The above may not give the desired result if more than one . appears in a file name.
For example tok.part1.part2 would become part2.tok.part1.
If you want part1.part2.tok instead, then you can use the following simple script.
#echo off
ren tok.* .*?.tok
for %%F in (.*.tok) do for /f "tokens=* delims=." %%A in ("%%F") do ren "%%F" "%%A"
For an explanation of how that 1st REN works in the 2nd script, see How does the Windows RENAME command interpret wildcards?
I suppose an esoteric argument could be made that a name like tok..name would become name.tok when it should be .name.tok. That could be fixed by using:
#echo off
setlocal disableDelayedExpansion
ren tok.* .*?.tok
for %%F in (.*.tok) do (
set "name=%%F"
setlocal enableDelayedExpansion
ren "!name!" "!name:~1!"
endlocal
)
The nice thing about the solutions above is they don't rely on the length of "tok". A string value of any length could be substituted for "tok" and the code works just as well.
The James L solution works well for a constant length. That solution can be improved a bit.
The 2nd argument to the substring operation is not needed. Removing it lets the solution work no matter how long the full original name is.
The code will fail if a name has an ! in it. Fixed by toggling delayed expansion on and off.
The filenames should be quoted in the REN statement in case of spaces or special characters
.
#echo off
setlocal disableDelayedExpansion
for %%i in (tok.*) do (
set "filename=%%i"
setlocal enableDelayedExpansion
ren "!filename!" "!filename:~4!.tok"
endlocal
)
you can also do the same without delayed expansion (which is slow).
Also, if there is only one dot, without explicitly using lengths of name parts.
%~n expands to filename without extension, and %~x to dot with extension (so I remove dot with :~1).
Also, using %* in for, you may pass arbitrary number of arguments.
And even more. If you add /R bewteen for and %%I (you'll get for /R %%I), it will recurse into subdirs also.
Whole batch file:
for %%I IN (%*) do call :Rename "%~I"
exit /b
:Rename
set newname=%~x1
ren %1 "%~dp1%newname:~1%.%~n1"
exit /b

Why does substring in for not work?

Using this batch file I want zip some *.txt files. Each *.txt file in its own zip file. Unfortunately it is not working and i get as output
ECHO is disabled (OFF).
several times. Here is the sourcecode:
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set filename = %%i
set filenametrunc = %filename:~0,10%
7z a -tzip -mx0 %zipname%
echo %filename% zipped.
)
I read something about EnableDelayedExpansion and activated it. Can't get it working though.
Any help appreciated.
You need to use SetLocal EnableDelayedExpansion and wrap variables in !. Also, don't put spaces between variable names, equals and the value.
set filename = ... makes a variable named %filename % with a value  ...
set filename=..... makes a variable named %filename% with a value .....
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set filename=%%i
set filenametrunc=!filename:~0,10!
7z a -tzip -mx0 !zipname!
echo !filename! zipped.
)
Variables in % inside brackets are evaluated all at the same time, which is before the entire loop starts executing. Your previous code would expand all variables before the set statement ran.
You need to initialize the variable zipname and expand the var using the ! character instead of the % character.
Read HELP SET, specifically
Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time.
and change your code to
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set zipname=%%i
7z a -tzip -mx0 !zipname!
echo !zipname! zipped.
)
Delayed expansion is only needed within the loop if you need to access a variable that you assign inside the loop. But there is no need in your case.
You need to 1st get the correct 7z syntax. Your original code was attempting to put all of the the files in the current directory into a single zip file because you didn't specify a filename. Also your ZIPNAME was uninitialized. You want something like the following.
7z a -tzip zipname filename
I presume you want the name of the zip to be the same as the original filename, except with a .zip prefix instead of .txt. Then all you need is the ~n modifier that gives the base name without the prefix. 7-Zip will automatically append the .zip extension.
for %%i in (*.txt) do 7z a -tzip %%~ni %%i
If you want you can add the -mx0 option, which does no compression. I can't imagine why you would do that for a text file.
for %%i in (*.txt) do 7z a -mx0 -tzip %%~ni %%i
If you want to add your own message
for %%i in (*.txt) do (
7z a -mx0 -tzip %%~ni %%i
echo %%i zipped into %%~ni.zip
)

Resources