0

I am currently trying my hand at batch, and wrote this file for counting .mkv and .srt files in a directory, which behaves in a way I don't understand:

@echo off
setlocal EnableDelayedExpansion
set /A mkvCounter=0
set /A srtCounter=0
set mkvFileName=empty

::Count .mkv files in directory
for %%f in (*.mkv) do (
    set /A mkvCounter=mkvCounter+1)
::Count .srt files in directory
for %%f in (*.srt) do (
    set /A srtCounter=srtCounter+1)

IF NOT %mkvCounter%==1 (
    echo There is more than 1 .mkv file in this directory
    set counter=1
    for %%f in (*.mkv) do (
        set a[!counter!]=%%f
        echo !counter!: %%f
        set /a counter=counter+1
    )
    :enterMkvNumber
    REM Check if the number is valid 
    echo select the number of the .mkv file that you want to merge
    set /p num="Number: "
    if not !num! GEQ -1 (
        echo Error invalid input, select number between 0 and !mkvCounter!
        GOTO :enterMkvNumber
    )
    if not !num! LEQ !mkvCounter! (
        set /A max=!mkvCounter
        echo Error invalid input, select number between 0 and !mkvCounter!
        GOTO :enterMkvNumber
    )
    echo Selected Mkv File: !a[%num%]!
)

endlocal
EXIT /B

The echo Selected Mkv File: !a[%num%]! line prints "Selected Mkv File: " when I execute the file and enter a valid number, indicating that !a[%num%]! returns nothing.

When I don't enter a valid number, i.e. the program prompts me to enter the number a 2nd time, and then enter a valid number echo Selected Mkv File: !a[%num%]! creates the desired output of "Selected Mkv File: myFile.mkv".

Example output:
There is more than 1 .mkv file in this directory
1: asdf.mkv
2: hehe.mkv
3: yep.mkv
select the number of the .mkv file that you want to merge
Number: 1
Selected Mkv File:

Does anyone know what causes this and/or how to fix it?

Crenshaw
  • 13
  • 5
  • 1
    You cannot jump around inside a code block using a GOTO. – Squashman Sep 24 '20 at 17:46
  • @Squashman what makes you say that? It worked fine for me. I did remove the `:enterMkvNumber` mark and replaced the GOTO statements with EXIT ones. `!a[%num%]!` still comes up empty on valid inputs when echoeing. – Crenshaw Sep 24 '20 at 17:52
  • `goto :Label` breaks any `(`block`)` context, that's what @Squashman wanted to say. If you need to go back in the code like this, you need to move all that portion out of the parenthesised block; you could place it in a sub-routine and [`call`](https://ss64.com/nt/call.html) it, because `goto` doesn't see the block before `call` ran; once you return from the sub-routine, the block context in the main section is still intact… – aschipfl Sep 24 '20 at 18:24
  • You set the value of `num` inside a code block. Because of that you would need some mechanism of double delayed expansion. You cannot use `num` with normal percent expansion as you already know because you used delayed expansion with the variable in your `IF NOT` comparison. – Squashman Sep 24 '20 at 21:59

1 Answers1

0

Give this one a spin. It uses macros to handle the definition of arrays, Dynamic menus and file selection.

@Echo Off & Setlocal DisableDelayedExpansion
::: ************************************************************** ||   Macro Definitions
::: Delayed expansion must be enabled AFTER definition of macros, and BEFORE their use.
 Set "TAB=  "
 Set "Menu=Echo/!DIV!&For %%n in (1 2)Do if %%n==2 ((Set "CHCS="&For %%G in (!Options!)Do (Set "Opt=%%~G"& Set "CHCS=!CHCS!!Opt:~0,1!"&Set "Opt[!Opt:~0,1!]=%%~G"& Set "Opt=[!Opt:~0,1!]!Opt:~1!"& Echo/!Opt!))&Echo/!DIV!& For /F "Delims=" %%o in ('Choice /N /C:!CHCS!')Do (For %%C in (!Opt[%%o]!)Do (Set "OPTION=%%C")))Else Set Options="
 Set "DEF/array=(If "!#$E!"=="" (Set "#$E=-1"))&For %%n in (1 2)Do if %%n==2 (Set /A "#$E+=1"&Set "$E=!$E!"&For %%G in (!$E!)Do (Set "$E[!#$E!]=%%~G"))Else Set $E="
rem // extension type provided using Substring modification to replace $E
 Set "SelectFile=(If Not !#$E! GTR 0 (Echo/No $E Files found. & Exit /B 0))& (For /L %%i in (0 1 !#$E!) Do If Not "!$E[%%i]!"=="" Echo/%%i:!TAB!!$E[%%i]!)&Echo/Select a $E file number [0-!#$E!]:&Set /P "FN=FN: "&For %%v in ("!FN!")do (If /I "!FN!"=="Exit" (Exit /B 0)Else If not "!$E[%%~v]!"=="" (Set "PATH[$E]=!$E[%%~v]!"&Echo/!$E[%%~v]! Selected)Else (Goto :$E))"
rem // selected path returned in !PATH[ext]!
::: ************************************************************** ||   End Macro Definitions
 Setlocal EnableExtensions EnableDelayedExpansion
::: Build Dividing line based on actual console dimensions.
 for /F "usebackq tokens=2* delims=: " %%W in (`mode con ^| findstr Columns`) do Set "Console_Width=%%%W"
 Set "DIV="&For /L %%i in (2 1 %Console_Width%)Do Set "DIV=!DIV!-"
::: ************************************************************** ||   Script Body
 Set "SourceDir=%~dp0"
 PUSHD "%SourceDir%"
 For %%O in (*.mkv)Do %DEF/array:$E=mkv%"%%~fO"
 For %%O in (*.srt)Do %DEF/array:$E=srt%"%%~fO"
:menu
 cls & Echo/.mkv Files:!#mkv! .srt Files: !#srt!
 %Menu%mkv Srt Exit
 If /I "!Option!"=="Exit" (POPD & Endlocal & Endlocal & Goto :Eof) Else Call :!Option!
 PAUSE
Goto :menu
:mkv
 %SelectFile:$E=mkv%
Exit /B 0
:srt
 %SelectFile:$E=srt%
Exit /B 0

Invalid input is flagged as the input is used to index the array element. False input results in an empty element which triggers a return to the extension label the selectFile macro is provided with at expansion via substring modification.

The breakdowns:

---------------------------------------------------------------------------------------

  • Menu Macro:
  • Display Dividing line with value in DIV variable and...
  • Use If else outer for loop to capture, modify and display the strings to be used for menu options.
  • The first character of each string is used as the CHOICE character for user selection
  • Will fail if multiple strings containing the same first character are supplied.
  • Assigns each string to an indexed value that is used to return the selected string in the OPTION variable
  • using the output of the Choice command which is captured using the For /F %%o loop.
 Echo/!DIV! & For %%n in (1 2)Do if %%n==2 (
  Set "CHCS="
  For %%G in (!Options!)Do (
   Set "Opt=%%~G"
   Set "CHCS=!CHCS!!Opt:~0,1!"
   Set "Opt[!Opt:~0,1!]=%%~G"
   Set "Opt=[!Opt:~0,1!]!Opt:~1!"
   Echo/!Opt!
  )
  Echo/!DIV!
  For /F "Delims=" %%o in ('Choice /N /C:!CHCS!')Do For %%C in (!Opt[%%o]!)Do Set "OPTION=%%C"
 )Else Set Options=

---------------------------------------------------------------------------------------

  • DEF/Array macro:
  • Expanded with substring modification, $E is replaced the the variable name to be used for a given array
  • Initial If condition Prepares an undefined Array for incrementation from a 0 index
  • Array element is captured using the If / Else outer for loop and assigned to the incremented index value in the array
 (If "!#$E!"=="" (Set "#$E=-1")) & For %%n in (1 2)Do if %%n==2 (
  Set /A "#$E+=1"
  For %%G in (!$E!)Do Set "$E[!#$E!]=%%~G"
 )Else Set $E=

---------------------------------------------------------------------------------------

  • SelectFile macro:
  • Tests the index value of array for a positive file count, returns to previous menu if fails
  • Iterates over array for the variable substitued with $E during expansio from 0 index and outputs defined files
  • and their index number for selection. Array name is shared with the relevant label to allow return to the correct label when
  • invalid input is supplied via Set /P for indexed file selection
  • Assigns filepaths to variable Path[$E], again, $E is replaced with the relevant file type via substring modification during expansion.
 If Not !#$E! GTR 0 (Echo/No $E Files found. & Exit /B 0)
 For /L %%i in (0 1 !#$E!) Do If Not "!$E[%%i]!"=="" Echo/%%i:!TAB!!$E[%%i]!
 Echo/Select a $E file number [0-!#$E!]:&Set /P "FN=FN: "&For %%v in ("!FN!")do (
  If /I "!FN!"=="Exit" (Exit /B 0)Else If not "!$E[%%~v]!"=="" (
   Set "PATH[$E]=!$E[%%~v]!"
   Echo/!$E[%%~v]! Selected
  )Else (Goto :$E)
 )

Note: code supplied for breakdowns is non-functional, it's just been deconstructed to allow you to more easily see the steps each macro takes to achieve the outcomes.

T3RR0R
  • 2,747
  • 3
  • 10
  • 25