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

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
)
)

Related

decrement of a number in filename with cmd on windows

I have a bunch of files:
CAR_003.dat
CAR_003.obj
CAR_004_prev0.png
CAR_004_prev1.png
CAR_004_tex0.tga
I need to rename them to:
CAR_002.dat
CAR_002.obj
CAR_003_prev0.png
CAR_003_prev1.png
CAR_003_tex0.tga
how I can do this with cmd on windows in a batch?
You need to execute the following batch in the directory you want.
It will rename everything in the tree.
#ECHO off
SETLOCAL EnableDelayedExpansion
FOR /R %%f in (CAR*) DO (
FOR /F "usebackq tokens=1,2,* delims=_" %%m in ('%%~nxf') do (
SET filePath=%%~dpf
SET filePrefix=%%m_
SET /a fileNumber=1%%~nn-1001
SET fileNumber=000!fileNumber!
SET fileNumber=!fileNumber:~-3!
SET filePosfix=%%~no
SET fileExt=%%~xf
IF [!filePosfix!] EQU [] (
SET fileRest=%%~xf
) ELSE (
SET fileRest=_!filePosfix!!fileExt!
)
REM ECHO %%f
REM ECHO !filePath!!filePrefix!!fileNumber!!fileRest!
REM ECHO ~~~~~~~
MOVE "%%f" "!filePath!!filePrefix!!fileNumber!!fileRest!"
)
)

Moving specific number of files into newly created numbered folders

I currently have around 550 files in a folder with the same format (.csv) and same headers (all started with the letters "YL").
I wonder if there is a way to splits these files (50 files at a time) (order doesn't matter) into numbered folders? (ex. 1, 2, 3, 4, 5) And also create a subsequent folder for the leftover files?
I have found this scripts and tried to modify it for 50 files, but it looks like it only created a the first folder (subdir1)
#echo off
set /a counter=1
set /a filesperfolder=50
cd dir\dir_main
:loopstart
set dirname=subdir%counter%
md %dirname%
echo %dirname%
dir /b | findstr /v /i "subdir*"> %temp%\temp.txt && for /l %%l in (1,1,%filesperfolder%) do #for /f "tokens=1,2* delims=:" %%a in ('findstr /n /r "^" %temp%\temp.txt ^| findstr /r "^%%l:"') do #move %%b %dirname%\%%b >nul
set /a counter=%counter%+1
for /f "tokens=*" %%a in ('type %temp%\temp.txt ^| find /c /v ""') do set _filesmoved=%%a
del %temp%\temp.txt
IF %_filesmoved% LSS 50 goto done
goto loopstart
:done
cls
echo All files were moved!!
pause
exit
I disliked the script you found as it was hard to read and used a temp file to keep track of the list of files. (Also, it evidently doesn't work, so there's that.)
#echo off
SET /a cnt=50
SET /a fnum=0
FOR /F "delims=" %%f IN ('dir /b /a-d *.csv') DO (
CALL :moveFile "%%f"
)
GOTO :end
:moveFile
IF "%cnt%" equ "50" CALL :makeDir
move "%~1" "%fnum%\%~1"
SET /a cnt+=1
GOTO :EOF
:makeDir
SET /a fnum+=1
mkdir %fnum%
SET /a cnt=0
GOTO :EOF
:end
Here is another way to do it. We test if there are still files in the directory, if there is, create a new directory and copy 50 files.
#echo off & setlocal enabledelayedexpansion
set fold_cnt=1
:test
set file_cnt=50
dir /a-d YL*.csv | findstr /IRC:"File(s)"
if %errorlevel% equ 0 (
mkdir !fold_cnt!
) else (
goto :eof
)
for %%i in (YL*.csv) do (
if not !file_cnt! equ 0 (
set /a file_cnt-=1
move /Y "%%i" "!fold_cnt!\%%i"
)
)
set /a fold_cnt+=1
goto test

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.

Loop over an interval of files

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

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