Reputation: 15
I need to delete all files with extensions which are not specified in the arguments (except .sys files). The problem is with an assignment of my variable.
Here are my commands (apologies for duplication, wasn't sure how to use or statement here):
@echo off
cls
cd test
for %%f in (*.*) do (
set exist = false
for %%a in (%*) do (
if %%~xf == .%%a set exist = true
if %%~xf == .sys set exist = true
)
if %exist% == false (
del %%f
)
)
pause
Would be very grateful for any suggestions on how to get this code working as expected by me.
Upvotes: 0
Views: 291
Reputation: 70923
The main problem with your code is the variable expansion. In batch files, when a command or a block of commands (several commands enclosed in parenthesis) are readed, they are parsed and then executed. During the parse phase, the variable read operations (%var%
) are removed from the code being replaced with the value inside the variable. Once this has been done, the command or block is executed.
All this means that when the code is executed, if you change a variable (exists
in your code), the changed value can not be retrieved while inside the same command/block, as there is not any variable read operation, only the value in the variable before starting the execute phase.
This can be avoided using setlocal enabledelayedexpansion
. This command allows you to change where needed the syntax used to read a variable from %var%
into !var!
, indicating to the parser that the variable expansion must be delayed until the command is executed, not during parse phase.
So, your code could be something like
@echo off
setlocal enabledelayedexpansion
cls
cd test
for %%f in (*.*) do (
set "exist=false"
for %%a in (%*) do (
if /i "%%~xf" == ".%%a" set "exist=true"
if /i "%%~xf" == ".sys" set "exist=true"
)
if "!exist!"=="false" (
del "%%f"
)
)
pause
Note that
set var = value
has been changed into set var=value
. Spaces are important, you were defining a variable called var[space]
with a value [space]value
all the variable assignments are quoted to prevent unneeded ending spaces included in the variable value. If spaces are included, the ==
test could fail. Being careful this is not needed, but it is a good habit.
quotes are being included to prevent problems with spaces in file names or extensions
the %exists%
has been changed to !exists!
so the changed value can be retrieved while inside the same block (for %%f
)
the if
extension comparisons include the /i
switch for case insensitive tests.
You should also note that when having delayed expansion enabled, the !
character becomes a problem as the parser will see it as part of a variable read operation. If you have files or extensions that could include this character, delayed expansion is a problem. It can be done but requires to only enable delayed expansion when really needed and disable again when not required.
@echo off
setlocal disabledelayedexpansion
cls
cd test
for %%f in (*.*) do (
set "exist=false"
for %%a in (%*) do (
if /i "%%~xf" == ".%%a" set "exist=true"
if /i "%%~xf" == ".sys" set "exist=true"
)
setlocal enabledelayedexpansion
if "!exist!"=="false" (
endlocal
del "%%f"
) else (
endlocal
)
)
pause
But, as in your case you are only changing the variable value between two values and the values are irrelevant, it is only a flag, you can ignore delayed expansion and the real value inside the variable and use an alternative syntax, if defined
to test if the variable contains or not a value. Your true/false
can be a defined/not defined
test
@echo off
setlocal enableextensions disabledelayedexpansion
cd test
for %%f in (*) do (
set "removeFile=1"
for %%x in (sys %*) do (
if /i "%%~xf"==".%%~x" set "removeFile="
)
if defined removeFile del "%%f"
)
pause
If the extension matches any of the arguments, the variable content is removed, that is, now the variable is undefined.
edit to adapt to Magoo's comments
When dealing with the filesytem elements, it is possible to see unexpected behaviours in the file/folders selection.
Files and folders that don't follow the 8.3
traditional naming (up to 8 characters for the name, up to 3 for the extensions, no special characters, no spaces) have what is known as a long name, but they also have a short 8.3
name associated to the long name. It can be seen using the /x
switch in the dir
command.
While not directly visible, these short names are checked when a wildcard search is done, resulting in files/folders selected with long file names or extensions not matching the requested wildcard expresion but with short names or extensions that do match the wildcard.
In case the short names or extensions needs to be processed inside for
loops, the modifiers used in for
replaceable parameters (ex. %%f
) to retrieve them are
%%~snxf Short name and short extension of the element being referenced by %%f
%%~snf Short name of the element being referenced by %%f
%%~sxf Short extension of the element being referenced by %%f
Upvotes: 3