Consider this hierarchy:
MainFolder\Sub_Folder1\Original_Files\
\Converted_Files\
\Sub_Folder2\Original_Files\
\Converted_Files\
Now in each ...\Original_Files\
I've a bunch of video files which I'll encode and save to the respective ...\Converted_Files\
.
I could do it for one subfolder with this batch code:
@echo off
set "sourcedir=G:\Animation\Anime\OnePiece\Episodes\Main"
set "outputdir=G:\Animation\Anime\OnePiece\Episodes\Converted"
PUSHD "%sourcedir%"
for %%F in (*.mkv) DO ffmpeg -i "%%F" -s 640x480 -map 0 -c:v libx265 "%outputdir%\%%F"
POPD
I've generated a text file with the folder paths of all the subfolders which contains:
G:\Animation\ToConvert\Berserk_1997_The_Complete_Series
G:\Animation\ToConvert\Blue_Exorcist
G:\Animation\ToConvert\Elfen_Lied
Every folder listed in the file has Main
and Converted
folders within them. I've to loop through all files in Main
and save into Converted
as you might see in above.
This is something I came up with :
@echo off
for /F "tokens=*" %%A in (f.txt) DO (
set "sourcedir=%A%\Main"
set "outputdir=%A%\Converted"
PUSHD "%sourcedir%"
for %%F in (*.mkv) DO ffmpeg -i "%%F" -s 640x480 -map 0 -c:v libx265 "%outputdir%\%%F"
POPD
) %%A
Running for /F "tokens=*" %A in (f.txt) DO @echo %A
gives me the names of the subfolders.
I thought somehow if I could pass the name to some variable and concatenate \Main
and \Converted
to it, it might work.
But on running the code above from within a command prompt window, it's just switching the current directory from the folder I'm running the batch file to C:\Windows
.
How can I run nested loops, one for the subfolders and then chose between working in Main
and saving in Converted
and the next loop for files in Main
?
Your last batch code fails because of
A
like an environment variable with %A%
instead of %%A
and(
and )
requires the usage of delayed expansion enabled before with the command line setlocal EnableDelayedExpansion
and using !sourcedir!
and !outputdir!
instead of %sourcedir%
and %outputdir%
which are already replaced by current value of the environment variables sourcedir
and outputdir
(empty string here as not defined before) when Windows command processor parses the entire command block before executing command FOR the first time.%%A
after closing parenthesis at end is unknown for Windows command interpreter and results therefore in an exit of batch processing because of a syntax error.However, better than your code which requires first the creation of a text file with the folder paths would be the usage of following code:
@echo off
for /D %%D in ("G:\Animation\ToConvert\*") do (
if exist "%%D\Main\*.mkv" (
echo Processing %%D ...
if not exist "%%D\Converted\*" md "%%D\Converted"
for %%I in ("%%D\Main\*.mkv") do (
ffmpeg.exe -i "%%I" -s 640x480 -map 0 -c:v libx265 "%%D\Converted\%%~nxI"
)
)
)
The outer FOR with parameter /D
finds just non hidden subfolders within folder G:\Animation\ToConvert
and holds in loop variable D
the name of the subfolder with full path not ending with a backslash.
The IF condition checks if in the current subfolder there is a folder Main
with 1 or more *.mkv files to process. If this condition is true,
Converted
is created if not already existing,Main
of current subfolder.The loop variable I
holds the name of the current *.mkv file with full path. So "%%I"
can be used for the input file as current directory does not matter because input file name is with full path.
For the output file the folder Converted
in current subfolder is specified and appended is with %%~nxI
the file name and the file extension of input file as name for the output file.
This batch code does not require delayed expansion as there is no environment variable used, only the loop variables D
and I
.
For completeness also your code using a text file containing line by line the folders to process with removing all unnecessary environment variables to make it possible to run the batch file without using the commands setlocal
and endlocal
.
@echo off
for /F "usebackq tokens=*" %%A in ("f.txt") do (
if exist "%%A\Main\*.mkv" (
echo Processing %%A ...
if not exist "%%A\Converted\*" md "%%A\Converted"
for %%I in ("%%A\Main\*.mkv") do (
ffmpeg.exe -i "%%I" -s 640x480 -map 0 -c:v libx265 "%%A\Converted\%%~nxI"
)
)
)
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
if /?
md /?
BTW: See this answer and the other answers linked there if you ever want to understand what delayed expansion is and what the commands setlocal
and endlocal
do not needed here.