DOS batch file For loop runs twice - for-loop

I have a batch file that recursively encodes videos to a sub folder "encode" then deletes the original and moves the new file to the original directory. The problem I'm having is that after each video is encoded, the for loop picks up the newly encoded video and runs again. After that, it moves on to the next video. I'm not sure why it runs twice instead of once or infinitely. What am I misunderstanding? I am a complete novice, so my apologies if it's a simple mistake.
#echo off
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.mp4, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause

The reason it processes twice is because the file conversion creates another video clip that matches the criteria in the FOR loop.
To avoid dealing with folder structures and syncing, a simple way to get around this is to split the process into two loops, performing the *.mp4 files first:
#echo off
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp4) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause
Don't forget to remove the *.mp4 from the second loop's file list.
Edit: Here's a solution that's more elegant.
#echo off
set /A count = 0
pushd %~dp0
for %%e in (mp4 mp2 mpg vob avi wmv mov m4v mpeg) do (
for /R %%f in (*.%%e) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
)
popd
echo Count is: %count%
pause
Make sure the mp4 is listed first so it's not reconverted once the other file types are processed.

I've tested it to see why it behaves so strangely like this, well, and the only answer I could come up with is that it simply acts strangely. my guess is that it depends on the order of operations.
this is my take on it:
in some implementations of the code, the for /r avoids an infinite loop. what it does, is run on the files that are not .mp4 first. then, probably because it was renamed, it doesn't recognize it as the same file.
probably, after it runs on the .mp4, the second time, it's file inode (except for the last time opened and edited) shouldn't be different at least to the point where the system won't recognize it as the same file anymore.
I tested a bit different version of the code that did produce an infinite loop:
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.mp4, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
move %%f %%~dpf\encode
rename %%~dpf\encode\%%f %%~dpf\encode\%%~nf.mp4
move %%~dpf\encode\%%~nf.mp4 %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause
and strangely, not only it ran an infinite loop, but it also created an infinite amount of subfolders named '\encode\encode\encode...', but the reason for that doesn't matter.
what's different in this version of the code, is that I always rename the files.
that is probably why it produces an infinite loop.
the for /r command reiterates files that have been renamed, and not necessarily on those edited.
the solution seems to be, indeed, to run the code on all .mp4 files first, and the other ones second.

Related

compressing multiple files into bzip2

so i found this nice batch for window that would compress every file of the same extension in the same directory into bzip2 by dragging and dropping any of the files into it but i would like to take it further and make it that when i drag and drop a folder into it. it would compress all the files in it, including the sub-folders until it reaches the end. obviously i would guess it has something to do with looping with using %%d but i could not exactly figure it out.
#echo off
if [%1]==[] goto usage
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for %%f in (%rootpath%) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
I share with you this helpful and well commented batch script posted by enteleform on superuser
I just modified this variable Set archivePath="%%~x.zip" to Set archivePath="%%~x.bz2"
How to make 7-zip do a whole bunch of folders
#Echo OFF
SetLocal EnableDelayedExpansion
Rem // 7-Zip Executable Path
Set sevenZip="C:\Program Files\7-Zip\7z.exe"
Rem // START: NewLine Variable Hack
Set newLine=^
Rem // END: NewLine Variable Hack !! DO NOT DELETE 2 EMPTY LINES ABOVE !!
Rem // Set ErrorLog Variables
Set errorCount=0
Set separator=--------------------------------------------------------
Set errorLog=!newLine!!newLine!!separator!!newLine!!newLine!
Set errorPrefix=ERROR #:
Set successMessage=All Files Were Successfully Archived
Rem // Loop Through Each Argument
SetLocal DisableDelayedExpansion
for %%x in (%*) do (
Rem // Use Current Argument To set File, Folder, & Archive Paths
SetLocal DisableDelayedExpansion
Set filePath="%%~x"
Set directoryFiles="%%~x\*"
Set archivePath="%%~x.bz2"
SetLocal EnableDelayedExpansion
Rem // Source Is A Folder
if exist !directoryFiles! (
Set sourcePath=!directoryFiles!
)
Rem // Source Is A File
if not exist !directoryFiles! (
Set sourcePath=!filePath!
)
Rem // Print Separator To Divide 7-Zip Output
echo !newLine!!newLine!!separator!!newLine!!newLine!
Rem // Add Files To Zip Archive
!sevenZip! A -TZIP !archivePath! !sourcePath!
Rem // Log Errors
if ErrorLevel 1 (
Set /A errorCount=errorCount+1
Set errorLog=!errorLog!!newLine!!errorPrefix!!sourcePath!
)
)
Rem // Print ErrorLog
if !errorCount!==0 (
Set errorLog=!errorLog!!newLine!!successMessage!
)
Echo !errorLog!!newLine!!newLine!!newLine!
Rem // Keep Window Open To View ErrorLog
pause
You could probably do that with a single line batch-file:
#For %%G In ("%~1")Do #If "%%~aG" GEq "d" (For /F Delims^= %%H In ('""%__AppDir__%where.exe" /R "%%~G" * 2>NUL|"%__AppDir__%findstr.exe" /EVIL ".bz2""')Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1)&"%__AppDir__%timeout.exe" /T 3
If you'd like it over multiple lines for readability:
#For %%G In ("%~1") Do #If "%%~aG" GEq "d" (
For /F "Delims=" %%H In (
'""%__AppDir__%where.exe" /R "%%~G" * 2>NUL | "%__AppDir__%findstr.exe" /EVIL ".bz2""'
) Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1
"%__AppDir__%timeout.exe" /T 3
)
These examples should only work if you drag and drop a directory onto it, or call it on the command line with a directory as the first argument.
#echo off
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for /R %%f in (*) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9 -x!"packall.bat"
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
Cheers to my friend Anya who found a solution, so the way it would work with the script above is that you make a batch file name it packall.bat
save it anywhere as it will delete itself at the end of the process.
when you want to compress bunch of files into bz2 you copy it and put it in inside a folder made with any name in your desktop.
make sure its name has no spaces nor its sub-folders as that may confuse batch and make it compress your desktop contents for some reason.
click on the batch, then it will compress all the files within the same folder its in and their sub-folders and automatically delete itself.
Video example:
http://billstuff.site.nfoservers.com/e79nwk69.mp4
IMPORTANT NOTE for some reason if there duplicate names of files with the same extension at sub-folders they will be deleted
Don't forget the folder and its sub-folder names should not have a space
Best of luck!

Batch, read filename backwards

I'm working on a little script that moves files to a different map sorted by the last 2 characters, now my problem is, files always look like this:
1238184AD
1237135881AD
123477TG
And my problem here is, I can move files to the correct map if they have a fixed length, but they are not fixed. Sow now my question is, can I count the filename backwards so that the script will make a directory of the last 2 characters.
This is how my current script looks like:
#ECHO OFF
setlocal enabledelayedexpansion
set index=~8,2
set moveFrom=C:\Users\**\Desktop\Map\
set moveTo=C:\Users\**\Desktop\Map2\
for /R "%moveFrom%" %%f in (*.txt) do (
echo %%f
set "fileName=%%~nf"
cd %moveTo%
IF EXIST "!fileName:%index%!" (
move /-y "%%f" "%moveTo%"!fileName:%index%!"\"
echo "%%f" moved
) ELSE (
mkdir "!fileName:%index%!"
move /-y "%%f" "%moveTo%"!fileName:%index%!"\"
echo "%%f" moved
)
)
pause

Moving files from Subfolders into root directory, but not copying them to the next directory when ran again

I have a folder that contains subfolders with MP4 files. I'm trying to write a script that will move the MP4 files out of the subfolders into the root folder when ran. The batch file I wrote is working, but when the batch script runs again for new subfolders, the MP4 files that were already copied to the root folder, get moved up another level in the file structure. For example:
C:\MainRoot\Root\Subfolder\media.mp4
When script is ran, 'media.mp4' gets moved up to C:\Root\media.mp4 as desired.
But since I need the script to run on a scheduled task. The next time the script runs I get the following:
C:\MainRoot\media.mp4
Instead of just the MP4 file staying in C:\MainRoot\Root.
Here's my batch file so far to copy the mp4 files:
set root_folder=C:\MainRoot\Root
for /f "tokens=1* delims=" %%G in ('dir %root_folder% /b /o:-n /s ^| findstr /i ".mp4" ') do (
move /y "%%G" "%%~dpG..\%%~nxG"
)
What do I need to modify so that once moved, the MP4 files will stay in place?
Any help would be greatly appreciated!
Since all your source files seem to be at a certain directory level, a for /D loop could be wrapped around your for /F loop, which parses the output of a non-recursive dir command line (no /S):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=C:\MainRoot\Root"
set "_PATTERN=*.mp4"
rem // Loop through sub-directories:
for /D %%D in ("%_ROOT%\*") do (
rem // Loop through matching files:
for /F "eol=| delims=" %%F in ('dir /B "%%~fD\%_PATTERN%"') do (
rem // Avoid overwriting destination file:
if not exist "%_ROOT%\%%~nxF" (
rem // Move matching file one level up:
move /Y "%%~fD\%%~nxF" "%_ROOT%\%%~nxF"
)
)
)
endlocal
exit /B
If you are happy to overwrite as in your provided example then something as simple as this may suit your purpose:
#Echo Off
Set root_folder=C:\MainRoot\Root
If /I NOT "%CD%"=="%root_folder%" PushD "%root_folder%" 2>Nul||Exit/B
For /R %%G In (*.mp4) Do If /I NOT "%~dpG"=="%root_folder%\" Move "%%G">Nul 2>&1
If the files are only one folder deep you may prefer this:
#Echo Off
Set root_folder=C:\MainRoot\Root
If /I NOT "%CD%"=="%root_folder%" PushD "%root_folder%" 2>Nul||Exit/B
For /D %%G In (*) Do Move "%%G\*.mp4">Nul 2>&1

Searching for string in multiple zip archives

Here's what I have;
On a windows-based web server there are roughly 1,000 zip files, each with dozens of log files inside. I already have a script that goes through each archive and deletes all but one specific file type (in an attempt to save diskspace and delete things I don't need). Then, the script unzips each archive to their own folder. And I know how to code the reverse of that to zip them back when I'm done.
Here's what I need to figure out;
Once I run the previously mentioned script (we call it garbageman because it cleans out the garbage in the zip files) I need to go through the remaining 5 or 6 files in each of the newly created unzipped folders, and look for a specific string in each file. If I find the string, I delete everything that is not that string, and save it to a file called "export.txt" in that folder. Then, I move to the next unzipped file, and so on. Once completed, I need re-zip everything back together into their own archives
Here's what I have for code so far. Any help is extremely appreciated.
cd "C:\Program Files\7-Zip"
FOR %%c in (C:\Users\xxxxxx\Desktop\LogQueue\*.*) DO 7z d %%c "-x!xstore*" -r
FOR /R "C:\Users\xxxxxx\Desktop\LogQueue" %%I in ("*.zip") do (
"%ProgramFiles%\7-Zip\7z.exe" x -y -o"%%~dpnI" "%%~fI"
)
cd "C:\Users\xxxxxxx\Desktop\LogQueue"
FOR /R "C:\Users\xxxxxx\Desktop\LogQueue" %%I in ("*.*") do (
findstr "xxxxxxxx_eReceipt" %%~fI > %%~dpnI\export.txt
pause
)
for /d %%X in (*) do "c:\Program Files\7-Zip\7z.exe" a "%%X.zip" "%%X\"
This is an edit:
This script should do what you want.
Only Change sourcedir and mystring variables.
export.txt will be inside a file called Storage in the root directory of the batch.
:ScriptA
#ECHO ON
MKDIR "%CD%\Storage"
MKDIR "%USERPROFILE%\Desktop\Outx"
GOTO :ScriptB
:ScriptB
::REM ONLY CHANGE
SET "sourcedir=%USERPROFILE%\Desktop\Test"
FOR /R "%sourcedir%\" %%a in (*.txt) do copy "%%a" "%CD%\Storage"
:ScriptC
:ScriptC
#ECHO OFF
SETLOCAL
SET "VARA=%CD%\Storage"
SET "VARB=%USERPROFILE%\Desktop\Out"
::REM ONLY CHANGE
SET "mystring=PUT_STRING_HERE"
FOR %%a IN ("%VARA%\*.txt") DO FINDSTR "%mystring%" "%%a">nul&IF NOT ERRORLEVEL 1 FINDSTR "%mystring%" "%%a">"%VARB%\%%~nxa"
DEL /F "%CD%\Storage\*.txt"
GOTO :ScriptD
:ScriptD
#ECHO ON
COPY /B "%USERPROFILE%\Desktop\Outx\*.txt" "%CD%\Storage\export.txt"
RD /S /Q "%USERPROFILE%\Desktop\Outx"
goto :eof

Batch Make 100MB Archive max with all files contained into a folder (Recursive)

I am looking to create a program that would zip (using 7zip) all files contained into the folder (Recursivly) into an archive until the archive hits 100MB. Whenever it does, it would join in the .csv file associated with the file, delete it, create a new one with the next number and also create a new archive. It should do this until all files are archived into an archive (number doesn't matter as long as all the files added into an archive)
My example is not considering files inside sub-folders yet. (yeah, gotta start somewhere)
The example does something a little counter-logical, it does remove the last added file from the archive once it sees it's bigger than 100MB. Problem is, i don't think batch can evaluate the output of the archive before creating it, therefore it's a little workaround. That way it manages to find the size of the archive and afterwards determine if it's ok to go or if were done with this one.
I'm doing this because we need zip files being maxed out 100MB. It doesn't matter if i get 10 or 20 .zip files, it only matters that none bust 100MB. After that we'll use the output archives and upload them to archive it all.
As you can see it also ECHO Name,Type,File,Event into the newer file because the headers are required into the .csv file. It is required to put a .csv file into every archive, and this is why once it spots the 100MB cap it deletes the last added file, then put in the .csv and afterwards deletes it.
I have already taken care of unique file size, none of them are going to be bigger than 40MB, and only those lesser than 40MB are considered.
Anyway this is what i have so far but it doesn't want to work, for some reason it closes ASAP after i doubleclick my .bat
SET /a modif=1
SET "file=importationinfo"
SET "reqext=.csv"
ECHO Name,Type,File,Event> %file%%modif%%reqext%
FOR %%a IN (*.*) DO (
IF NOT %%~zi GTR 40999999 (
IF /i NOT "%%~nxa"=="%~nx0" (
IF /i NOT "%%~nxa"=="%file%%modif%%reqext%" (
FOR /f "delims=" %%b IN ("%%~dpa\.") DO (
>>"%file%%modif%%reqext%" ECHO "%%~nxa","4","\%%~nxa","%ID%"
"C:\Program Files\7-Zip\7z.exe" a -tzip Import%modif%.zip "%%~nxa"
FOR /F %%i IN ("Import%modif%.zip") DO SET "size=%%~zi"
ECHO %size%
IF %size% GTR 104857599 (
ECHO Bigger than 104857599
REM This Echo is only for debugging
"C:\Program Files\7-Zip\7z.exe" d -tzip Import%modif%.zip "%%~nxa"
PAUSE
"C:\Program Files\7-Zip\7z.exe" a -tzip Import%modif%.zip "%file%%modif%%reqext%"
DEL %file%%modif%%reqext%
SET /a modif+=1
ECHO Name,Type,File,Event> %file%%modif%%reqext%
) ELSE (
ECHO NOT 100MB YET
>>"%file%%modif%%reqext%" ECHO "%%~nxa","4","\%%~nxa","%ID%" )
)
)
)
)
)
That is all. I really hope you guys can help me out on this.
Thanks.
J-P.
EDIT : I know it is possible to ask for maximum file size to 7z and zip them alltogether, and it'll automatically create multiple archives with .001 .002 ... filenames afterwards. But in this specific case this option is not OK, as the archives will not be used to recreate these files but to archive them (upload using .zip format). Therefore if any files is split into two different archive, this will cause problems. This is also why i want to join in a new .csv in every archive.
you might test this:
#ECHO OFF &SETLOCAL
SET "archive=test\archive"
SET "startfolder=%userprofile%"
SET /a maxsize=104857600
for /f "tokens=1*delims=:" %%a in ('dir /s /b /a-d "%startfolder%" ^| findstr /n $') DO (
IF %%~za gtr %maxsize% (ECHO "%%a" too large (%%~za Bytes^) &GOTO :EOF)
SET "$%%a=%%~fb"
SET "filecount=%%a"
)
SET /a ptr=1
SET /a anr=1
:loop
CALL SET "file=%%$%ptr%%%"
ECHO adding "%file%" TO %archive%-%anr%.7z
START /b /w "7zip" "7za" a "%archive%-%anr%" "%file%" >NUL||(ECHO Error!&GOTO :EOF)
FOR %%a IN ("%archive%-%anr%.7z") DO SET "asize=%%~za"
IF %asize% gtr %maxsize% (
ECHO deleting "%file%" FROM %archive%-%anr%.7z
START /b /w "7zip" "7za" d "%archive%-%anr%" "%file%" >NUL||(ECHO Error!&GOTO :EOF)
SET /a anr+=1
) ELSE (
SET /a ptr+=1
)
IF %ptr% leq %filecount% GOTO :loop
ECHO %filecount% file(s) added IN %anr% archive(s).
Note #1: the script doesn't work with = in file or path names
Note #2: the script will terminate, if it finds a file with a size greater than the archive size
Note #3: archive names will be created from archive-1.7z, archive-2.7z...
Note #4: because testing compression takes much time, I havn't tested very much
Note #5: because of your special needs the script works very slowly
Accepting Answers: How does it work?.

Resources