I recently started converting all my video files to MP4 for streaming purposes, and was using batch so far without issues. Now I have 6000+ videos to convert and needed some sort of queue system I could manipulate.
This is my current code to convert everything from directories into commands in a separate folder.
@echo off
setlocal disabledelayedexpansion
set dirs=D:\ANIME E:\ANIME F:\ANIME
for %%a in (%dirs%) do (
echo %%a
pushd %%a
for /f "tokens=* delims= " %%f IN ('dir/b/s *.avi *.mkv *.m4v *.mpeg *.mpg') do (
echo D:\handbrake\HandBrakeCLI.exe -i "%%f" -e qsv_h264 -q 20 -E fdk_haac -B 196 -R Auto -D 0,0,0,0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback copy:* --subtitle=1 --subtitle-default --subtitle-forced --subtitle-burn -o "%%~dpf%%~nf.mp4" > "D:\batch\%%~nf.bat"
echo del /F "%%f" >> "D:\batch\%%~nf.bat"
)
)
This works great and makes me 1000's of bat files to call and that is where the issue arises. A lot of files have special characters like ! in their names which messes up the for loop I use to loop through these. I set the file to read-only before processing, so my other batch won't try to convert the same file (I run 3 at once).
I found a workaround using ENABLEDELAYEXPANSION, but after a few loops I will get the error saying I exceeded the maximum calls for that.
@echo off
setlocal enableextensions
echo Starting loop
goto loop
:loop
for %%f in (D:\batch\*.bat) do (
set ATTRIBS=%%~af
setlocal enabledelayedexpansion
set READ_ATTRIB=!ATTRIBS:~1,1!
if !READ_ATTRIB!==- (
setlocal disabledelayedexpansion
attrib +R "%%f"
call "%%f"
)
timeout /t 2 /nobreak
goto loop
)
endlocal
Normally you'd say just change the ! variables to % and remove delayedexpansion, but that gives me errors in getting the file attributes.
set READ_ATTRIB=%ATTRIBS:~1,1%
if %READ_ATTRIB%==- (
Will give me no result and the error ( is unexpected If I echo READ_ATTRIB the result will be ~1,1 always and when echoing others I will get ECHO IS OFF.
Is there any way to not use delayedexpansion or in a way that I won't get errors after a few loops?
32 is the deepest level of setlocal
when used in batch file. You need to use setlocal
- endlocal
pair analogously to a pair of (
left and )
right parentheses. See capitalized ENDLOCAL
below.
@echo off
setlocal enableextensions
echo Starting loop
goto loop
:loop
for %%f in (D:\batch\*.bat) do (
set ATTRIBS=%%~af
setlocal enabledelayedexpansion
set READ_ATTRIB=!ATTRIBS:~1,1!
if !READ_ATTRIB!==- (
setlocal disabledelayedexpansion
attrib +R "%%f"
call "%%f"
ENDLOCAL
)
ENDLOCAL
timeout /t 2 /nobreak
REM this was totally mazy: goto loop
)
endlocal
Moreover, latter goto loop
in your original code causes that for %%f
loop is initialised over and over indefinitely against the same data set, i.e. %%f
in the loop body refers to the only file all the time. See capitalized REM
.