Batch, unattended args in for loop - batch-file

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

Related

Batch rename filename in subfolder

What do I have to change here in this code so it could do also subfolders?
Or if it is easier to run only through subfolders?
#echo off
setlocal enableDelayedExpansion
for %%F in (*.jpg) do (
set "name=%%F"
ren "!name!" "!name:_=!"
)
This runs ok in current folder it erase in jpg filename character "_", but I don't know how to do it in subfolders, and that is my main goal to do.
It is possible to use a For /R loop:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /R . %%G In ("*_*.jpg") Do (
Set "name=%%~nxG"
SetLocal EnableDelayedExpansion
If Not Exist "%%~dpG!name:_=!" Ren "%%G" "!name:_=!"
EndLocal
)
I have used a . character after /R to signify the current directory as the recursion base, whilst this is not necessary, because the current directory is assumed if no path is provided, it serves as a reminder, the you could include another path there if needed.
Although you could also use a For /F loop, with the Dir command:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F "EOL=? Delims=" %%G In ('Dir /B/S/A:-D "*_*.jpg"') Do (
Set "name=%%~nxG"
SetLocal EnableDelayedExpansion
If Not Exist "%%~dpG!name:_=!" Ren "%%G" "!name:_=!"
EndLocal
)
In this case, if you wanted to use a directory other than the current directory, you can insert it directly in the Dir glob, e.g. "C:\SomePath\*_*.jpg"
Please note however, in both cases, no attempt has been made to ensure that the remaining string, after removal of the underscores is a valid filename. It is your responsibility to incorporate such a check, if you wish to have robust code in your environment. Additionally no check is included to ensure that short filenames, (8.3), are not matched, so if this could be an issue in your target environments, then you should include modifications or additions to cater for that.

Trying use a batch file to delete filenames appended with numbers

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.

I need to create a list of folders that contain a specific file type with a batch file

Using a batch file I'm trying to generate a list of only folders within a location that contain a certain file type, let's call it *.abc
at the moment I only know how to echo a DIR command output to a file called folder.lst, I would like to expand on that and try to either
a) echo only folders containing the *.abc file type to folder.lst
b) remove references in folder.lst of folders that do not contain the *.abc file type.
I also tried having a FOR loop check each line to see if a *.abc file existed in that location and skip it, if not, but I just could not get that to work, here is an example of what I had.
setlocal enableextensions enabledelayedexpansion
FOR /F "delims=" %%C in (folder.lst) do (
set temp=%%C
if not exist !temp!\*.abc (goto skip) else (goto resume)
:resume
then my actions live here
:skip
)
but I am aware I am doing something wrong here...I just do not know what.
Maybe the /R form of the for command will help:
for /r "basedir" %%a in (.) do if exist "%%~a\*.abc" (
echo %%a contains .abc file(s)
)
The %%a will be the directories you want (with a trailing \., but you should be able to not care or accommodate this).
There are problems with such of the script as you have posted in that you can'y use labels within a block statement. You've also not provided any examples.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "lastdir="
FOR /r "%sourcedir%" %%a IN (*.abc) DO IF "!lastdir!" neq "%%~dpa" (
SET "lastdir=%%~dpa"
ECHO %%~dpa
echo "!lastdir:~0,-1!"
)
GOTO :EOF
Each directory found will be echoed twice - one with the trailing \ and once without.
You would need to change the setting of sourcedir to suit your circumstances.
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
for %%a in ("%root%") do for /f "delims=: tokens=2" %%b in ('
dir /a-d /s "%root%\*.abc" ^| find "\"
') do echo(%%~da%%~pnxb
This executes a recursive dir command searching for the indicated file type under the starting point (change root variable to suit your needs). For each found folder we retrieve the folder from the dir header that precedes the file list (the lines that contain a backslash).
To separate the path from the rest of the information in the line, the colon is used as delimiter. As this will leave the drive out of the retrieved information, an aditional for is used to retrieve the drive from the folder reference.
From the command line:
for /f "delims=" %a in ('dir /s /b *.abc') do echo %~dpa >> folders.lst
In a batch file:
for /f "delims=" %%a in ('dir /s /b *.abc') do echo %%~dpa >> folders.lst
The above commands will place only the folder names containing the *.abc files in folders.lst.
Notes:
% should be replaced by %% when the command is used in a batch file.
The ~dp part of %~dpa expands %a to a drive letter and path only. Remove the d if you don't want the drive letter. The p path includes a trailing \ which may be interpreted as an escape character by some commands.
The above commands start the search in the current directory. To search from the root of the current drive you can do cd \ first.
For more information see FOR /F Loop command: against the results of another command and Parameters.

Rename files using batch file script

I want to rename the all PDF files in folder using batch script. for example i have 3 files in folder:-
anyfile.pdf
otherfile.pdf,
another.pdf
Now i want to rename file as bellow:-
PDF0.pdf
PDF1.pdf,
PDF2.pdf
i have fetch the files using this script:-
#ECHO OFF
SETLOCAL DisableDelayedExpansion
SET "r=%__CD__%"
FOR /R . %%F IN (*.pdf) DO (
SET "p=%%F"
SETLOCAL EnableDelayedExpansion
ECHO(!p:%r%=!
ENDLOCAL
)
pause
now i can rename please help me.
Thanks
Are you just looking for the command to rename files? Its ren. Look at http://ss64.com/nt/ren.html for more info.
FOR /R and the string replacement to get rid of the path seem unnecessary here, since you stay within one directory.
(generally, if you want to get of the path, just say %%~nxFwhich returns the Name and eXtension of %%F.)
you can perform arithmetics, ie. count a number up, with SET /A, so you could do simply
#ECHO OFF
setlocal enabledelayedexpansion
set i=0
FOR %%F IN (*.pdf) DO (
set /a i=i+1
ren %%F PDF!i!.pdf
)
pause

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

Resources