2

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?

Mofi
  • 46,139
  • 17
  • 80
  • 143
daddyodevil
  • 184
  • 2
  • 13
  • For your task I would use two nested `for /D` loops to iterate the two directory levels in the main folder, and then a standard `for` loop to iterate the `*.mkv` files... in your last script you need [delayed expansion](http://ss64.com/nt/delayedexpansion.html) as you write and read the same variable within a single block of code... – aschipfl Aug 16 '16 at 07:40
  • @aschipfl Can you share a code because I dont know batch programming. All I'm doing is googling and mixing matching syntaxes !!!!!! – daddyodevil Aug 16 '16 at 07:43

2 Answers2

3

Your last batch code fails because of

  1. referencing the loop variable A like an environment variable with %A% instead of %%A and
  2. referencing environment variables defined/set within a command block defined with ( 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.
  3. %%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,

  • an information message is output to see progress on running the batch file,
  • in current subfolder the folder Converted is created if not already existing,
  • another FOR loop is executed to process each *.mkv file found in the folder 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.

Community
  • 1
  • 1
Mofi
  • 46,139
  • 17
  • 80
  • 143
  • Thanks for the answer man, works as it should. And damn your answer was just awesome, will you tell where can I learn Windows Shell programming or whatever it is called like you ?? Considering I've the Main and Converted folders created i ran a simpler code which I am giving below. Thanks again mate. – daddyodevil Aug 16 '16 at 14:45
  • 1
    I'm quite sure all experts in batch script writing started with reading (help of command, documentation, articles in www) and trying it out, reading more and trying more, and so on until getting experience in batch script writing. Testing each line of a batch script must be done nevertheless nearly always because syntax checking occurs on script execution as there is no preprocessing and compilation step like for C/C++/C# and other programming languages. SS64's [An A-Z Index of the Windows CMD command line](http://ss64.com/nt/) is very helpful for beginners. – Mofi Aug 16 '16 at 14:53
1

@Mofi wrote a great answer, both his codes work flawlessly. This is just a simpler version I am running because the conditions being checked in that program are already met.

@echo off
for /F "tokens=*" %%A in (f.txt) DO (
        for %%F in (%%A\Main\*.mkv) DO ffmpeg -i "%%F" -s 640x480 -map 0 -c:v libx265 "%%A\Converted\%%~nxF"
)
daddyodevil
  • 184
  • 2
  • 13
  • `%%A\Main\*.mkv` on second __FOR__ loop should be enclosed in double quotes as otherwise the batch file would fail on a folder path with 1 or more spaces or another critical character like ``&()[]{}^=;!'+,`~`` in path. – Mofi Aug 16 '16 at 14:57