Loop over an interval of files - cmd

I would like to define a for-loop (windows command line) that iterates over (numbered) intervals of files in a directory, say 1..100, and then 101..200, and 201..300 etc [Edit: regardless of the files names]. See following pseudo-code:
for %WORKDIR% %%f(1..100) in (*.htm) do (
REM DoSomething with %%f
)
for %WORKDIR% %%f(101..200) in (*.htm) do (
REM DoSomething with %%f
)
...etc
Q: Is there a way to define "numbered intervals" of files from command line?
// Rolf

You can place each function in a separate file:
:1to100
setlocal enabledelayedexpansion
set /a "file=1"
rem Skip 0 (skip=0 is omitted because it's illegal) and process 100.
for /f %%f in ('dir %workdir%\*.htm /b') do (
if !file! gtr 100 (exit /b) else (set /a "file+=1")
echo Do something with %%f.
)
endlocal
goto :eof
:100to200
setlocal enabledelayedexpansion
set /a "file=1"
rem Skip 100 and process 100.
for /f "skip=100" %%f in ('dir %workdir%\*.htm /b') do (
if !file! gtr 100 (exit /b) else (set /a "file+=1")
echo Do something with %%f.
)
endlocal
goto :eof

Related

How to break a "for /l" loop in a batch script?

I'm a newbie the commands of a Batch Script on Windows
I have a question about a batch file that I'm writing.
How to break from the "for /l" loop ?
In the script below, I would like to copy x number files from one folder to another
However, after the break the first loop, the second loop doesn't works fine,
it copied all files in the source folder to the destination folder.
Thank you for your help :)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET Source=C:\Data
SET Target1=C:\Work\bak1
SET Target2=C:\Work\bak2
SET Target3=C:\Work\bak3
SET /A days=13
SET /A weekNum=9
SET /A MaxLimit=3
SET /A Count=0
for /l %%x in (1, 1, %days%) do (
if %%x LEQ 9 (
FOR /F %%G IN ('DIR /B "%Source%"\*.*') DO (
copy /y "%Source%"\"%%G" "%Target1%"
set /a Count=Count+1
if !Count!==%MaxLimit% call :step1
)
:step1
REM SET /A "x=x + 1"
REM echo %%x
IF %%x LEQ 1 IF %weekNum% EQU 9 (
FOR /F %%G IN ('DIR /B "%Source%"\*.*') DO (
copy /y "%Source%"\"%%G" "%Target2%"
set /a Count=Count+1
if !Count!==%MaxLimit% call :step2
)
:step2
REM SET /A "x=x + 1"
REM echo %%x
)
) else (
REM Copy file to Target3
)
)

Batch variable store result from command

It seems for me a very simple question, however I am struggling a lot with this and don't find an answer yet.
My aim is to count occurences of a specific string in a file.
I do or try to do this using following command:
for /f "tokens=2 delims=;" %%a in ('path to file with searchstring') do (
set count=('path to file I am searching in' find /c "%%a")
if !count! NEQ 0 echo !count!
)
Seems straightforward for me however the second line seems to be wrong as the script exits.
I want to save the result of findin a var because I only wants to outpout Nonzero resutls.
Here's an example batch-file using findstr, for better word matching, (It uses the filenames from your previous question):
#(For /F "UseBackQTokens=2Delims=;" %%G In ("classID.txt")Do #(Set "count=0"
For /F %%H In ('^""%__AppDir__%findstr.exe" /IN "\<%%G\>" "trc.txt"^"'
)Do #(Set /A count+=1)&SetLocal EnableDelayedExpansion
If !count! Gtr 0 (Echo %%G: !count!)&Endlocal))&Pause
Here it is fully parenthesized over multiple lines for you to better understand:
#Echo Off
For /F "UseBackQ Tokens=2 Delims=;" %%G In (
"classID.txt"
) Do (
Set "count=0"
For /F %%H In (
'^""%__AppDir__%findstr.exe" /I /N "\<%%G\>" "trc.txt"^"'
) Do (
Set /A count +=1
)
SetLocal EnableDelayedExpansion
If !count! Gtr 0 (
Echo %%G: !count!
)
Endlocal
)
Pause
And a fully parenthesized example of it outputting the results to a file named results.txt:
#Echo Off
(
For /F "UseBackQ Tokens=2 Delims=;" %%G In (
"classID.txt"
) Do (
Set "count=0"
For /F %%H In (
'^""%__AppDir__%findstr.exe" /IN "\<%%G\>" "trc.txt"^"'
) Do (
Set /A count +=1
)
SetLocal EnableDelayedExpansion
If !count! Gtr 0 (
Echo %%G: !count!
)
Endlocal
)
)>"results.txt"

Equalise the number of files with windows batch

I have a script that is designed to count the number of files with a value in the filename (****_1.jpg), compare it with the number of files with another name (****_2.jpg) and delete the larger number of files so the number of files are equal for each type.
This is what I've got so far
#echo off
setlocal enableextensions
set count1=0
set count2=0
for %%f in (.\seq\*_1.jpg) do set /a count1+=1
echo "1 " %count1%
for %%f in (.\seq\*_2.jpg) do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "%count2% + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "%count1% + %%A _2.jpg"
)
endlocal
I can get the counts, I make it to my if statements and then nothing happens. What am I missing?
For now I'm trying to echo a list of files I'm about to delete.
In addition to the need for ENABLEDELAYEDEXPANSION, there really is no record of file names from either set. The "count" cannot be used to create the filename, can it?
I put in some code at the top to create a test set. Always referencing THEDIR obviates the need to hardcode a directory name in many places.
When you think it will work, remove echo from the DEL command line.
#echo off
setlocal enableextensions enabledelayedexpansion
set "THEDIR=.\seqtest"
if not exist "%THEDIR%" (mkdir "%THEDIR%")
for /l %%i in (1, 1, 5) do (echo %%i >"%THEDIR%\file_%%i_1.jpg")
for /l %%i in (1, 1, 7) do (echo %%i >"%THEDIR%\file_%%i_2.jpg")
set count1=0
set count2=0
for %%f in ("%THEDIR%\*_1.jpg") do set /a count1+=1
echo "1 " %count1%
for %%f in ("%THEDIR%\*_2.jpg") do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
set /a "dcount=0"
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_1.jpg"`) do (
echo DEL "%%~f"
set /a "dcount+=1"
if !dcount! EQU !count! (goto Outa2)
)
for /l %%A in (1,1,%count%) do echo "%count2% + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
set /a "dcount=0"
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_2.jpg"`) do (
echo DEL "%%~f"
set /a "dcount+=1"
if !dcount! EQU !count! (goto Outa2)
)
)
:Outa2
:TheEnd
exit /b 0
If you want to delete any _1 file that does not exist as an _2 file and vice versa, you could loop over the _1 files and delete any for which no _2 file exists. Then, loop over the _2 files and delete any for which no _1 file exists.
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_1.jpg"`) DO (
set "FN=%%~f"
set "BASE=!FN:~0,-6!"
if not exist "%THEDIR%\!BASE!_2.jpg" (echo DEL "%THEDIR%\!BASE!_1.jpg")
)
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_2.jpg"`) DO (
set "FN=%%~f"
set "BASE=!FN:~0,-6!"
if not exist "%THEDIR%\!BASE!_1.jpg" (echo DEL "%THEDIR%\!BASE!_2.jpg")
)
As I understand this problem, you have two lists of files and you want to delete files from the larger list so both lists have the same number of files. Right? For example:
1_1.jpg 1_2.jpg
2_1.jpg 2_2.jpg
3_1.jpg 3_2.jpg
4_2.jpg
5_2.jpg
In previous example you want to delete 4_2.jpg and 5_2.jpg, correct? If the first list is the larger one, the files must be deleted from it; if both lists have the same number of files, no files be deleted. This solution do that:
#echo off
setlocal
rem Enter to the folder with files
cd seq
rem Get the first list of files
dir /B *_1.jpg > first.txt
rem Merge the first list...
< first.txt (
rem ... with the second list
for %%f in (*_2.jpg) (
rem For each file in second list, read a file from first list
set "first=" & set /P "first="
if not defined first ( rem The second list is larger: cut it
ECHO del "%%f"
)
)
rem If still are files in first list, it is larger: cut it
for /F "delims=" %%f in ('findstr "^"') do ECHO del "%%f"
)
I think, Your method for searching for all *.jpg files is little buggy. You should try this following approach instead. I've modified the code to check the code a little - but you'll get the idea.
#echo off
setlocal EnableDelayedExpansion enableextensions
set count1=0
set count2=0
for /f %%f in ('Dir /s /b "Photo\*.jpg"') do set /a count1+=1
echo "1 " %count1%
for /f %%f in ('Dir /s /b "Photo\*.Png"') do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "!count2! + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "!count1! + %%A _2.jpg"
)
endlocal
pause >nul
You can change the searching path from - "Photo\*.jpg" to anything in both cases. And this one has given me desired result on the CMD. I Hope this will work fine for you.
...
echo "2 " %count2%
set /a count=count1-count2
set "count=%count:-=%"
if %count1% gtr %count2% (
...
You evidently want to calculate count and need a method to find its absolute value.
simply subtract one vale from the other, then replace any - in the result with nothing.
From the prompt, see set /? for documentation.

how to compare numeric variables in batch files

why doesn't this work?
SET FIRST=""
SET COUNT=0
FOR %%F IN (dir *.png) DO (
IF %COUNT% NEQ 0 GOTO _skip
SET FIRST=%%F
:_skip
ECHO "%%F",
SET /A COUNT=COUNT+1
)
It sets FIRST to the last *.png because the IF condition fails, because COUNT - although is incremented by set /A, the IF %COUNT% doesn't ever work. Very frustrating.
Don't need to count, just do goto skip after echo line.
#echo off
for /f "delims=" %%f in ('dir /b *.png') do (
rem :: you can use "echo %%f" instead of "set first=%%f"
set first=%%f
goto _skip
)
:_skip
echo %first%
you mixing two things to scan folder.
Here is the second way:
#echo off
for %%f in (*.png) do (
set first=%%f
goto _skip
)
:_skip
echo %first%
exit /b 0
If you need absolutely to count, here is the way to skip with count. As stated in comment, you need to enable delayedExpansion
#echo off
set count=1
for %%f in (*.png) do (
set first=%%f
setlocal enabledelayedexpansion
if "!count!"=="1" goto _skip
endlocal
set /a count+=1
)
:_skip
echo !first!

for command is executed only for the first value when a label is inside

I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd

Resources