Ok, so I'm still pretty new to batch scripting and I have this problem with my code that I'm using setlocal enabledelayedexpansion in my code for the for loop, the For loop goes through folder names in a specific directory, but the problem is that some of the names may include "!"(exclamation marks) and if that is the case they are not counted for in the "!filename!" and when the code creates a new directory it does not include the "!". Also when the xcopy tries to copy the files from the original folder, the folder is not found, because the variable "!filename!" is not the same as the original(does not have the exclamation point).
So I found that for this I need to only add "setlocal enable delayed expansion" to some parts of the code and turn it off at other, but I cant seem to find the right places.
The code:
#ECHO OFF
setlocal enabledelayedexpansion
SET Location_Folder=V:
SET Destination_folder=V:\Nonimportable
SET Check_file_validation=V:\Nonimportable\result.txt
SET Excluded_folder=Nonimportable
set "lineNr=12"
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set filename=%%O
call D:\somefolder\otherfolder\batscriptname.bat !filename!
set Validation=
echo !filename!| FINDSTR /i /c:"%Excluded_folder%" >NUL
IF ERRORLEVEL 1 (
for /F "skip=12 delims=" %%a in (%Check_file_validation%) do if not defined Validation (
set Validation=%%a
call :valid
)
) else (
echo This folder name is excluded: !filename!
)
)
goto Finish
:valid
echo !Validation!| FINDSTR /c:"1" >NUL
if ERRORLEVEL 1 (
set Folder_path=%Location_Folder%\!filename!
set New_Folder_path=%Destination_folder%\!filename!
mkdir "!New_Folder_path!"
echo D | xcopy /o /y /q /s /v "!Folder_path!" "!New_Folder_path!"
rmdir /s /q "!Folder_path!"
) else (
echo Folder is valid !filename!
goto Finish
)
:Finish
exit /b
The Call part calls another small (~5lines) batch file that checks the sqlplus server if the "!filename!" is valid
EDIT: The whole code works fine and does what it should, unless there is a "!" in the name of some folder.
The problem is the parameter expansion in set filename=%%O.
In %%O is still the exclamation mark, but when delayed expansion is enabled, the bangs are dropped.
The conclusion is simple, delayed expansion have to be disabled when you expand a FOR parameter.
But when you also need delayed expansion?
You simply toggle the mode.
setlocal DisableDelayedExpansion
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set "filename=%%O" -- Here the DelayedExpansion have to be disabled
setlocal EnableDelayedExpansion
call D:\somefolder\otherfolder\batscriptname.bat filename
set "Validation="
...
endlocal
)
See also my modification of the CALL myBat.bat filename instead of CALL myBat.bat !filename!.
You shouldn't use content with CALL, better use a variable by reference and in your function take the content by
set "_filename=!%1!"
It's because CALL itself has some nasty behaviour with spaces, carets, etc
If you use a variable within a code block (parenthesised series of commands) then %var% will yield the value of the variable when the block is originally encountered (ie parse-time value) and !var! the value of the variable as it changes during the block (ie "run-time" value).
If you call a procedure - internal or external, then the values of the variables that the procedure sees are the run-time values from the parent. If these values are changed within the called procedure then the same rules apply, and the changed values are returned to the parent procedure.
However if you invoke setlocal then any value-variation made is reverted to its original value if you execute an endlocal instruction or reach end-of-file within the context of the setlocal.
OK - so that's how delayedexpansion works.
In your case, there is no need for delayedexpansion at all. In the loop in the mainline (%%O) you can use %%O in place of !filename!. In the :valid procedure, you can move the two set commands outside of the code block and then there's no need at all to use !vars! since no access is required to variables whose values change within blocks.
#ECHO OFF
setlocal
SET Location_Folder=V:
SET Destination_folder=V:\Nonimportable
SET Check_file_validation=V:\Nonimportable\result.txt
SET Excluded_folder=Nonimportable
set "lineNr=12"
For /f "tokens=*" %%O in ('dir /b /a:d "%Location_Folder%"') do (
set filename=%%O
call D:\somefolder\otherfolder\batscriptname.bat %%O
set Validation=
echo %%O| FINDSTR /i /c:"%Excluded_folder%" >NUL
IF ERRORLEVEL 1 (
for /F "skip=12 delims=" %%a in (%Check_file_validation%) do if not defined Validation (
set Validation=%%a
call :valid
)
) else (
echo This folder name is excluded: %%O
)
)
goto Finish
:valid
set Folder_path=%Location_Folder%\%filename%
set New_Folder_path=%Destination_folder%\%filename%
echo %Validation%| FINDSTR /c:"1" >NUL
if ERRORLEVEL 1 (
mkdir "%New_Folder_path%"
echo D | xcopy /o /y /q /s /v "%Folder_path%" "%New_Folder_path%"
rmdir /s /q "%Folder_path%"
) else (
echo Folder is valid %filename%
rem redundant instruction : goto Finish
)
:Finish
exit /b
Related
I have this simple batch code to check the Date Modified on a sub-folder (specifically the Recycle Bin.)
This search works flawlessly when manually input in Command Prompt, but not batch.
And using the same exact code to check other folders it works just fine. Help?
Code:
if exist C:\$Recycle.Bin (
pushd "C:\$Recycle.Bin"
for /F "delims=" %%a in ('dir /S /b S-1-*-1001 /AD') do set {file}=%%a
for %%a in ("%{file}%") do echo Recycle Bin: %%~ta
popd
)
The reason this is not working in batch is for one annoying feature of IF statements with the SET command. As stated by This Post - "cmd expands variables when commands are parsed, not when they are run. It so happens that an if or for statement with a block ( ... ) (or actually any block) counds as a single command in that case. So when you set variables inside a block and try using them in the same block there are no variables anymore – they were replaced by the values the variables had before the block even executed." - Joey
To fix this you can simply not put your code block inside the IF statement but rather use an ELSE and have it goto an :EOF
Option 1: - Avoid IF Statement W/H Code Block
#ECHO OFF
Rem | Check If Directory Exists & pushd It.
if exist "C:\$Recycle.Bin" (pushd "C:\$Recycle.Bin") ELSE (goto :EOF)
Rem | Grab data on folders
for /F "delims=" %%a in ('dir /S /b S-1-*-1001 /AD') do (set "{File}=%%a")
Rem | Display data on folders
for %%a in ("%{file}%") do (echo Recycle Bin: %%~ta)
Rem | Un-pushd
popd
pause
goto :EOF
If you do however wish to use a block inside the IF statment you will need to use setlocal enabledelayedexpansion at the top of your script. Furthermore, to echo or read brackets you will have to use !{File}! over %{File}%.
Option 2: - Properly expand IF Statement W/H Code Block
#ECHO OFF
#setlocal enabledelayedexpansion
if exist "C:\$Recycle.Bin" (
pushd "C:\$Recycle.Bin"
for /F "delims=" %%a in ('dir /S /b S-1-*-1001 /AD') do (set "{File}=%%a")
for %%a in ("!{file}!") do (
Set "data=%%~ta"
echo Recycle Bin: !data!
)
popd
) Else (Goto :EOF)
pause
goto :EOF
I have created a batch file in a windows server to parse the name of the files stored in a folder.
The name of the file contains a set of parameters splitted by the hyphen, e.g.
ACC-INV-APR-2015
I need to check the syntax correctness of the first two parameters (department and document type) e.g. I would avoid that the hyphen is inserted more than a time in the file name.
On the basis of the check, the files with wrong syntax will be moved to a folder.
We have to consider that, apart the first two parameters that are mandatory, the other ones could be skipped and therefore the file name could have some repetitive hypens after the first two parameters, e.g.
FIN-DOC-APR-2015--MFH-P01
We would avoid to have some file name like: FIN--DOC-APR-2015-MFH-P01
I have created the following batch file but I don't know how to skip the filename with wrong syntax....
Thank you.
setlocal EnableDelayedExpansion
set source=\\fileserver\share$\archive
set dest_ok=\\fileserver\share$\fileok
set dest_not=\\fileserver\share$\error
FOR /R %source% %%f in (*.*) do call :Proc1 "%%f"
goto End
:Proc1
Set filename=%1%
For %%A in (%filename%) do (
Set Folder="%%~dpA"
Set Name=%%~nxA
)
for /f "tokens=1,2 delims=- " %%a in ("%Name%") do call :Proc2 %%a %%b
goto :eof
:Proc2
set department=%1
set typedoc=%2
FINDSTR /x "%department%" c:\0_scripts\arch\departments.txt
if %errorlevel%==0 FINDSTR /x "%typedoc%" c:\0_scripts\arch\typedocs.txt
if %errorlevel%==0 move /Y %filename% %dest_ok%
if %errorlevel%==1 move /Y %filename% %dest_not%
goto :eof
:End
Sounds like a job for regular expressions. The Windows utility findstr will let you match based on a regular expression. It exits status 0 if found, non-zero otherwise. This lends itself to conditional execution. In a cmd console, enter findstr /? for details on supported regexp syntax.
It'll also speed things up to cache the contents of departments.txt and typedocs.txt into variables, rather than open, read, close, repeat for each file checked.
So, with that in mind, here's how I'd do it:
#echo off
setlocal
set "source=\\fileserver\share$\archive"
set "dest_ok=\\fileserver\share$\fileok"
set "dest_not=\\fileserver\share$\error"
set "departments.txt=c:\0_scripts\arch\departments.txt"
set "typedocs.txt=c:\0_scripts\arch\typedocs.txt"
setlocal enabledelayedexpansion
for /f "usebackq delims=" %%I in ("%departments.txt%") do set "dept=%%~I;!dept!"
for /f "usebackq delims=" %%I in ("%typedocs.txt%") do set "type=%%~I;!type!"
endlocal & set "dept=%dept%" & set "type=%type%"
for /r "%source%" %%I in (*) do (
rem // Does filename match /^[a-z]+-[a-z]+/i ?
echo %%~nxI | findstr /i "^[a-z][a-z]*-[a-z][a-z]*" >NUL && (
rem // Yep. Check whether department and doc type is in allowed list.
for /f "tokens=1-2 delims=- " %%a in ("%%~nxI") do (
// if %dept% doesn't equal itself with %%~a removed, and so on...
setlocal enabledelayedexpansion
if not "%dept%"=="!dept:%%~a=!" if not "%type%"=="!type:%%~b=!" (
// All checks passed. Moved to OK folder.
move /y "%%~fI" "%dest_ok%"
)
endlocal
)
)
// If the file hasn't been moved by now, it must've failed a test.
if exist "%%~fI" move /y "%%~fI" "%dest_not%"
)
C:\0_scripts\arch>(
echo MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf | findstr /i "^[a-z][a-z]*-[a-z][a-z]*" 1>N
UL && (for /F "tokens=1-2 delims=- " %a in ("MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf") do (
setlocal enabledelayedexpansion
if not "TEF6;TEF10;QMM8;QMM73;QMM72;QMM71;QMM7;QMM6;QMM13;QMM1;QMM;MFP2;MFP1;MFH3;MFH2;MFH1;MFH ;MFG3;MFG22;MFG21;MFG2;
MFG11;MFG1;MFG;MFB;HSE;COS;" == "!dept:%~a=!" if not "WPL;WP;WBP;WB;WAL;WAG;WA;VTL;VTK;VDP;VBT;VBL;VB;VAW;VAP;VA;UVA;UMV
;TSS;TRN;TKU;TDC;SYM;SWD;SWC;SW;SVS;SVA;SV;STR;STL;STF;STB;SPC;SBT;SAM;RTZ;RTP;RPL;RP;RNO;RHW;RAW;QMP;QMA;QM;QBG;QB;QAM;
PZB;PUM;PRV;PRS;PRJ;PRA;PQP;PPM;PPK;PP;PNR;PLB;PH;PFH;PDV;PDR;PDC;PDB;PAP;PAL;PAG;OPS;OPL;OEE;NOR;NKA;MUB;MSZ;MON;MOD;MB
B;MNT;LZT;LZS;LZN;LPV;LPN;LPL;LPC;LPA;LHT;LDP;LBA;KSB;KPV;KPA;KOE;KOB;KBU;KBL;KB;IAM;HZG;HZ;HSE;HRB;HFG;HF;HE;HAZ;GMD;GE
Z;GBB;FVT;FRM;FPL;FPK;FPI;FPA;FP;FMP;FME;FMD;FMA;FLP;FLB;FIM;FHW;FGY;FGV;FGS;FGP;FGL;FGK;FGE;FGD;FGB;FGA;FDA;FA;EZZ;EWZ;
EWS;EVT;EV;ETZ;ETL;ESZ;EPB;EP;ECM;DVL;ECR;DV;DRX;DRW;DRV;DRQ;DRK;DRF;DMD;DIF;DLP;DER;DDI;DBL;DB;DAT;D01;CPC;CIP;CHL;CE;C
AP;BVT;BVS;BVB;BV;BUG;BSV;BST;BSS;BS;BPZ;BLD;BDL;BBL;BBD;BB;BAL;BAD;ANH;AGZ;AFK;AEN;AED;AAW;AA;" == "!type:%~b=!" (
move /y "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" "\\server1\digit$\errori"
pause
)
endlocal
) )
if exist "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" move
/y "\\server1\digit$\deposito\MFH3\MFH3-FHW-20150529-F001MD14895-20301231-V01-OP20-TRIFLEX-CP1_H--.pdf" "\\server11\digit$\ok"
pause
)
1 file(s) moved.
Press any key to continue . . .
Blockquote
I have changed the script and came back to your original version .
This is the output of the batch file when a file correct is processed:
if exist "\server1\digit$\deposito\MFH3\MFH3--FHW-20150512-F01MD14861-20301231-V02-OP20-TRIFLEX-CP1H--.pdf" move
/y "\server1\digit$\deposito\MFH3\MFH3--FHW-20150512-F01MD14861-20301231-V02-OP20-TRIFLEX-CP1H--.pdf" "\server1\
digit$\errori"
pause
)
1 file(s) moved.
Press any key to continue . . .
C:\0_scripts\arch>(
echo MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf | findstr /i "^[a-z][a-z]-[a-z][a-z]" 1>NU
L && (for /F "tokens=1-2 delims=- " %a in ("MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf") do (
setlocal enabledelayedexpansion
if not "TEF6;TEF10;QMM8;QMM73;QMM72;QMM71;QMM7;QMM6;QMM13;QMM1;QMM;MFP2;MFP1;MFH3;MFH2;MFH1;MFH ;MFG3;MFG22;MFG21;MFG2;
MFG11;MFG1;MFG;MFB;HSE;COS;" == "!dept:%~a=!" if not "WPL;WP;WBP;WB;WAL;WAG;WA;VTL;VTK;VDP;VBT;VBL;VB;VAW;VAP;VA;UVA;UMV
;TSS;TRN;TKU;TDC;SYM;SWD;SWC;SW;SVS;SVA;SV;STR;STL;STF;STB;SPC;SBT;SAM;RTZ;RTP;RPL;RP;RNO;RHW;RAW;QMP;QMA;QM;QBG;QB;QAM;
PZB;PUM;PRV;PRS;PRJ;PRA;PQP;PPM;PPK;PP;PNR;PLB;PH;PFH;PDV;PDR;PDC;PDB;PAP;PAL;PAG;OPS;OPL;OEE;NOR;NKA;MUB;MSZ;MON;MOD;MB
B;MNT;LZT;LZS;LZN;LPV;LPN;LPL;LPC;LPA;LHT;LDP;LBA;KSB;KPV;KPA;KOE;KOB;KBU;KBL;KB;IAM;HZG;HZ;HSE;HRB;HFG;HF;HE;HAZ;GMD;GE
Z;GBB;FVT;FRM;FPL;FPK;FPI;FPA;FP;FMP;FME;FMD;FMA;FLP;FLB;FIM;FHW;FGY;FGV;FGS;FGP;FGL;FGK;FGE;FGD;FGB;FGA;FDA;FA;EZZ;EWZ;
EWS;EVT;EV;ETZ;ETL;ESZ;EPB;EP;ECM;DVL;ECR;DV;DRX;DRW;DRV;DRQ;DRK;DRF;DMD;DIF;DLP;DER;DDI;DBL;DB;DAT;D01;CPC;CIP;CHL;CE;C
AP;BVT;BVS;BVB;BV;BUG;BSV;BST;BSS;BS;BPZ;BLD;BDL;BBL;BBD;BB;BAL;BAD;ANH;AGZ;AFK;AEN;AED;AAW;AA;" == "!type:%~b=!" (
move /y "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" "\bars
rv11\digit$\ok"
pause
)
endlocal
) )
if exist "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" move
/y "\server1\digit$\deposito\MFH3\MFH3-AFK-20150511-F01MD12340-20301231-V07-OP20-TRIFLEX-CP1_H--.pdf" "\server1\
digit$\errori"
pause
)
1 file(s) moved.
Press any key to continue . . .
I'm doing a job, copying files from one location to another location using BATCH file. I split my statements into three parts, one program driver, one for generating file list under each sub-directory, and one for checking file name & doing actual copy stuff.
1.PROGRAM DRIVER
IF EXIST TEMP.TXT DEL TEMP.TXT
CD>TEMP.TXT
set /p ROOT=<TEMP.TXT
rem PARA is the date to copy
SET PARA=2013-08-06
ECHO %PARA%
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO ( ::COPY SUB-LOGIC FILE TO EACH SUB-DIRECTORY
ECHO NOW IN %%A
CD %%A
XCOPY "%ROOT%\WORK.BAT" . /K /Y
XCOPY "%ROOT%\CORE.BAT" . /K /Y
ECHO LOOP OUT.
)
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
ECHO NOW IN %%A
CD %%A
CALL WORK.BAT ::GENERATING FILE LIST
ECHO LOOP OUT.
)
CD %ROOT%\%PARA%
FOR /R %%A IN (.) DO (
ECHO NOW IN %%A
CD %%A
CALL CORE.BAT ::DOING COPY STUFF
ECHO LOOP OUT.
)
PAUSE
2.WORK.BAT
IF EXIST FILE.TXT DEL FILE.TXT
FOR %%B IN (*.wav) DO ECHO %%~nxB>>FILE.TXT
3.COPYING STUFF
FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET CCC="FALSE" ::IF NO CCC DECLARED HERE,BELOW FOR LOOP WILL BE SKIPPED
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
SETLOCAL
SET RES="FALSE"
IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET RES="TRUE"
) ELSE ( SET RES="FALSE")
ENDLOCAL& SET CCC=%RES% *::VAR CCC NOT UPDATED*
PAUSE
IF %CCC% EQU "TRUE" (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
:END
ECHO LOOP OUT
My question is, why my "ENDLOCAL & SET" statement not working, i.e., NULL each time, as pictures show. How can I change my statements to make it work as expected?
I changed part 3 to
FOR %%F IN ("%CD%") DO SET CURDIR=%%~nxF
IF NOT EXIST FILE.TXT GOTO END
SET "RES="
PAUSE
FOR /F %%C IN (FILE.TXT) DO (
SET "RES="
IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET "RES=Y"
) ELSE ( SET "RES=" )
PAUSE
IF DEFINED RES (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
It seems that RES always defined, even FILENAME is in specified ranges. In this case, it copied wrong files.
in (3)
FOR /F %%C IN (FILE.TXT) DO (
SETLOCAL
SET RES="FALSE"
IF "%%C" GEQ "CH201_00000000_000.WAV" SET RES="TRUE"
IF "%%C" LEQ "CH300_FFFFFFFF_FFF.WAV" (
SET RES="TRUE"
) ELSE ( SET RES="FALSE")
ENDLOCAL& SET CCC=%RES% *::VAR CCC NOT UPDATED*
PAUSE
IF %CCC% EQU "TRUE" (
IF NOT EXIST D:\PHILIPS\%PARA%\%PARA%\%CURDIR% MD D:\PHILIPS\%PARA%\%PARA%\%CURDIR%
XCOPY "%ROOT%\%PARA%\%CURDIR%\%%C" D:\PHILIPS\%PARA%\%PARA%\%CURDIR% /K /Y
)
)
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
Where flags are involved, the situation changes again. set "flag=" will ensure a flag is cleared. set "flag=somethingelse" will ensure it is set (the value is not relevant.) Using if defined flag (doiftrue) else (doiffalse) works on the run-time (current) status of flag - not the parse-time value.
Hence, I suggest you change your processing, setting ccc to either nothing with a set "ccc=" statement or something with a set "ccc=y" and you can then test for true/false using if [not] defined ccc
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
(on revised code)
Your tests are incorrect.
res will not be set to Y with value CH145... against CH201...
But it will be set to Y in the LEQ test as CH145... is lestt than or equal to CH300...
You may either cascade the setting:
if "%%C" GEQ "CH201..." IF "%%C" LEQ "CH300..." set "res=Y"
or gate the test
IF "%%C" GEQ "CH201_00000000_000.WAV" SET "RES=Y"
if defined res IF "%%C" GTR "CH300_FFFFFFFF_FFF.WAV" SET "RES="
I have a directory with many sub-directories that contain thousands of jpgs. What I want to do is create a batch script that will go through all of the sub-directories and delete every 2nd image i.e. keep the first, third, fifth image but delete the second, fourth, and six image etc per directory (ordered by filename).
I tried with the following but my knowledge of batch scripting is poor, and the syntax is clearly incorrect.
#echo off
set z = 0
for /f %%a in ('dir/b *.jpg')
do (
set z = z + 1
if z == 2 del %%a
)
The DO must be on the same line as FOR.
You must use SET /A if you want to do math
Your logic is wrong - Currently it will only delete the 2nd file, not every other one. You should take the mod 2 value (remainder devided by 2) and delete if the result is 0.
You must use %z% if you want to see the current value (except within a SET /A statement). But that will not work inside a code block that just set the value. In that case you need to enable delayed expansion and use !z! instead.
Expanding a FOR variable that contains ! (valid in file names) while delayed expansion is enabled will corrupt the value. So delayed expansion must be toggled on and off
You say you want to recurse sub-directories, but your code only looks at one folder.
Spaces are significant in the SET statement. Your code defines a variable z with a space at the end of the name. Not what you want.
Here is a debugged version:
#echo off
setlocal
for /r %%D in (.) do (
set "z=0"
for /f %%F in ('dir /b "%%D\*.jpg"') do (
set /a "z+=1, r=z%%2"
setlocal enableDelayedExpansion
if !r! equ 0 del "%%D\%%F"
endlocal
)
)
There are ways to solve this without delayed expansion. One is to simply alternate between defining and undefining a variable.
#echo off
setlocal
for /r %%D in (.) do (
set "del="
for /f %%F in ('dir /b "%%D\*.jpg"') do if defined del (
del "%%D\%%F"
set "del="
) else set "del=1"
)
Another is to intentionally divide by 0 when you want to delete, and delete only when there is an error. Error messages are hidden by 2>nul, and the || operator conditionally executes the following command only if the prior command failed.
#echo off
setlocal
for /r %%D in (.) do (
set "z=0"
for /f %%F in ('dir /b "%%D\*.jpg"') do 2>nul set /a "z+=1, 1/(z%%2)" || del "%%D\%%F"
)
try this and remove the echo if the output looks good:
#echo off &setlocal
for /f "tokens=1*delims=:" %%a in ('dir /b /s /a-d *.jpg^|findstr /n $') do (
echo %%a|findstr "[02468]$" >nul && echo del "%%~b"
)
There is a folder which contains some random files:
file1.txt
file2.exe
file3.cpp
file4.exe
How to SIMPLY display exe files connected with numbers like this:
1. file2.exe
2. file4.exe
And then I enter the number of the file, which I want to delete.. If it is even possible to do this simply..
Shortest bullet proof solution I can come up with. Like Anders, the DEL statement is disabled by the ECHO command. Remove the ECHO to make the menu functional.
#echo off
setlocal disableDelayedExpansion
for /f "delims==" %%A in ('set menu 2^>nul') do set "%%A="
for /f "tokens=1* delims=:" %%A in ('dir /b *.exe 2^>nul ^| findstr /n "^"') do (
set menu%%A=%%B
echo %%A. %%B
)
if not defined menu1 exit /b
set "delNum="
set /p "delNum=Delete which file (enter the number): "
setlocal enableDelayedExpansion
if defined menu!delNum! echo del "!menu%delNum%!"
The only thing I can think of that could go wrong is part of the menu could scroll off the screen if there are too many entries.
Additional messages can easily be incorporated. and an ELSE condition could be appended to the input validation to deal with invalid input.
A few subtle points of the code:
FINDSTR /N provides incrementing file number. Avoids need for delayed expansion or CALL within menu builder loop. Delayed expansion should not be enabled when expanding a FOR variable containing a file name because it will corrupt names containing !.
: is a safe FOR delimiter because a file name cannot contain :.
delNum is cleared prior to SET /P because SET /P will preserve existing value if <Enter> is pressed without entering anything.
Checking for the existence of the variable is the simplest way to validate the input. This is why it is critical that any existing MENU variables are undefined prior to building the menu.
Must use delayed expansion in IF DEFINED validation, otherwise space in input could crash the script (thanks Anders for pointing out the flaw in the original code)
DEL target must be quoted in case it contains spaces, even when delayed expansion is used.
Added test to make sure at least one menu entry exists before continuing. There may not be any .exe files left to delete.
#echo off
setlocal EnableDelayedExpansion
set i=0
for %%f in (*.exe) do (
set /A i+=1
set file[!i!]=%%f
echo !i!. %%f
)
set i=0
set /P i=File to delete:
del !file[%i%]!
Not exactly pretty but it gets the job done
#echo off
setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
goto main
:addit
set /A end=end + 1
set %end%=%~1
echo %end%. %~1
goto :EOF
:main
set end=0
for %%A in ("*.exe") do (
call :addit "%%~A"
)
if "%end%"=="0" goto :EOF
echo.&set idx=
set /P idx=Delete (1...%end%)
if not "%idx"=="" if %idx% GEQ 1 if %idx% LEQ %end% (
for /F "tokens=1,* delims==" %%A in ('set %idx% 2^>nul') do (
if "%idx%"=="%%~A" (
echo.Deleting %%~B...
rem del "%%~B"
)
)
)