Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
544 views
in Technique[技术] by (71.8m points)

windows - Batch file - Make Variable Menu

I have a menu here that you can navigate using keys using the choice command. The problem is that I want this menu to have a variable number of options. At the moment, if there are more than 3 drives detected, it will list only 3 of them. If there are less, it will list some options of N/A. Is there an easy way (without set /p) to make this exact menu with the same navigation method, but with variable options? Here's the link to the code I'm talking about

:list1
cls
setlocal EnableDelayedExpansion
echo Drives:
echo -------------------
echo ^> Drive !1a!
echo.
echo   Drive !2a!
echo.
echo   Drive !3a!
echo.
echo Other options:
echo -------------------
echo   Exit
echo.
echo   Back
echo.
echo Use WSX to navigate this menu.
endlocal
choice /c WSX /n >nul
if "%errorlevel%" == "1" goto list5
if "%errorlevel%" == "2" goto list2
if "%errorlevel%" == "3" goto list1a
goto list

:list2
cls
setlocal EnableDelayedExpansion
echo Drives:
echo -------------------
echo   Drive !1a!
echo.
echo ^> Drive !2a!
echo.
echo   Drive !3a!
echo.
echo Other options:
echo -------------------
echo   Exit
echo.
echo   Back
echo.
echo Use WSX to navigate this menu.
endlocal
choice /c WSX /n >nul
if "%errorlevel%" == "1" goto list1
if "%errorlevel%" == "2" goto list3
if "%errorlevel%" == "3" goto list2a
goto list2

:list3
cls
setlocal EnableDelayedExpansion
echo Drives:
echo -------------------
echo   Drive !1a!
echo.
echo   Drive !2a!
echo.
echo ^> Drive !3a!
echo.
echo Other options:
echo -------------------
echo   Exit
echo.
echo   Back
echo.
echo Use WSX to navigate this menu.
endlocal
choice /c WSX /n >nul
if "%errorlevel%" == "1" goto list2
if "%errorlevel%" == "2" goto list4
if "%errorlevel%" == "3" goto list3a
endlocal
goto list3

:list4
cls
setlocal EnableDelayedExpansion
echo Drives:
echo -------------------
echo   Drive !1a!
echo.
echo   Drive !2a!
echo.
echo   Drive !3a!
echo.
echo Other options:
echo -------------------
echo ^> Exit
echo.
echo   Back
echo.
echo Use WSX to navigate this menu.
endlocal
choice /c WSX /n >nul
if "%errorlevel%" == "1" goto list3
if "%errorlevel%" == "2" goto list5
if "%errorlevel%" == "3" goto end
goto list4

:list5
cls
setlocal EnableDelayedExpansion
echo Drives:
echo -------------------
echo   Drive !1a!
echo.
echo   Drive !2a!
echo.
echo   Drive !3a!
echo.
echo Other options:
echo -------------------
echo   Exit
echo.
echo ^> Back
echo.
echo Use WSX to navigate this menu.
endlocal
choice /c WSX /n >nul
if "%errorlevel%" == "1" goto list4
if "%errorlevel%" == "2" goto list1
if "%errorlevel%" == "3" goto menu1
goto list4
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Should anyone be looking for a variable menu navigation through choice (Or Dynamic Menu for general purposes), it is easily possible to build a variable menu using choice, String concatenation and substring modification.

The below is an example script that demonstrates a macro that builds and outputs the options available for the current menu. The command to be executed on the selected option is supplied using substring modification as exampled.

@Echo off
::: ************************************************************** ||   Macro Definitions
::: Delayed expansion must be enabled AFTER definition of macros, and BEFORE their use.
::: Menu Building Macro
::: Usage: %Menu:$CMD=command to be executed referencing !option!%Options as String List
::: !!! Limitation: Options and Labels beginning with the same Character cannot be used within the same menu
::: Define Command/s to be executed upon selection of a string option using substring modification to replace $CMD
:::  - Commands cannot use `%` or `=` characters. Selected string is accessed using the !Option! return variable
    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"& $CMD)))Else Set Options="
::: ************************************************************** ||   End of Macro Definitions
 Setlocal EnableExtensions ENABLEdelayedexpansion & Rem //      Required for Macro Usage.
::: 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 (Usage examples)
:MainMenu
 Cls
 Echo/- Call example
 %Menu:$CMD=Call :!Option! TF%Title Color
 Echo/- aqcuisition menu example
 %Menu:$CMD=Set /A !Option!+=1%Water Food
 Echo/!Option! = !%Option%!
 Echo/- Goto example
 %Menu:$CMD=Goto :!Option!%Title Color Exit
::: ************************************************************** ||   Script Break
:Title
 Echo/ Title %0
 Timeout 1 > Nul
::: return if Called Else (Goto :label) -Alternative option is to allow script continuation
 If not "%~1"=="" (Exit /B 0)Else Goto :MainMenu
:Color
 Echo/ Color %0
 Timeout 1 > Nul
 If not "%~1"=="" (Exit /B 0)Else Goto :MainMenu
:Exit
 Echo/ Exit %0
Exit /B 0

Below is a pratical application of the above, minus the remarks, with a colortext function to add color to each menu option.

@ECHO Off & Goto :main
:ColorMenu
 rem Set /A "RR=!random! %%195 + 60","GG=!random! %%195 + 60","BB=!random! %%195 + 60"
 rem Set "%~1=%/E%38;2;!RR!;!GG!;!BB!m!%~1!%/E%0m"
 Set "rV="& IF "!#A!"=="" (Set #A=32)
 (For %%C in ("!%~1!")Do Set "rv=!rV!%/E%!#A!m%%~C%/E%0m"& Set /A "#A+=1"& IF "!#A!"=="37" (Set #A=31)) & Set "%~1=!rV!"
Exit /B 0
:main
(Set LF=^


%= empty lines above are required. =%)
For /F eol^=^%LF%%LF%^ delims^= %%A in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"') do Set "TAB=%%A"
 For /F %%a in ('echo prompt $E ^| cmd')do (Set "/E=%%a[")
 Set "ChoList=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 Set "Menu=For %%n in (1 2)Do if %%n==2 (!DIV!&Set "CH#=0"&(Set "CHCS="&For %%G in (!Options!)Do For %%i in (!CH#!)Do (Set "CHCS=!CHCS!!ChoList:~%%i,1!"&Set "Opt[!ChoList:~%%i,1!]=%%~G"& Set "Opt=%%~G" &Call :ColorMenu Opt &<Nul Set /P "=[!ChoList:~%%i,1!] !Opt!"&Set /A "CH#+=1"&Echo/))&!DIV!& For /F "Delims=" %%o in ('Choice /N /C:!CHCS!')Do (Set "OPTION=!Opt[%%o]!"))Else Set Options="
 rem /* outdated */ Set "Menu=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!"&Call :ColorMenu Opt &Echo/!Opt!))&!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"&For %%G in (!$E!)Do (Set "$E[!#$E!]=%%~G"))Else Set $E="
 Set "DEL/array=(Set "#$E="&(For /F "Tokens=1,2 Delims==" %%G in ('Set $E[ 2^> Nul ')Do Set "%%G=" > Nul 2> Nul ))"
 Set "GetFiles=(For /F "Delims=" %%O in ('Dir /B *.$E /O:-D')Do %DEF/array%"%%~fO")"
 Set "SelectFile=%DEL/array% & %GetFiles% & If "!#$E!"=="" (!DIV!&Echo/No $E files in !CD!&!DIV!&Goto :Eof)Else For %%n in (1 2)Do If %%n==2 (Set "Ext=$E"&Set "FN="&(If /I "!#$E!"=="-1" (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]!)&!DIV!&Echo/[%/E%36mExit%/E%0m] or Select a $E file number [%/E%36m0%/E%0m-%/E%36m!#$E!%/E%0m]:&!DIV!&Set /P "FN=FN: "&For %%v in ("!FN!")do (If /I "!FN!"=="Exit" (Exit /B 0)Else If /I "!FN!"=="E" (Exit /B 0)Else If not "!$E[%%~v]!"=="" (Set "PATH[$E]=!$E[%%~v]!"&!DIV!&Echo/!$E[%%~v]! Selected)Else (Echo/invalid file index&!DIV!& Timeout 1 /Nobreak > Nul & Goto :!rLabel! )))Else Set rLabel="
 Set "GetFolders=%DEL/array% & Set "#$E="&For /F "Delims=" %%O in ('Dir /B /A:D')Do %DEF/array%"%%~fO""
 Set "SelectFolder=Set "FN="&(If /I "!#$E!"=="-1" (Echo/No Folders found in !CD!.))& (For /L %%i in (0 1 !#$E!) Do If Not "!$E[%%i]!"=="" Echo/%%i:!TAB!!$E[%%i]!)&!DIV!&Echo/[%/E%36mExit%/E%0m ^| %/E%36m..%/E%0m] Select a $E number [%/E%36m0%/E%0m-%/E%36m!#$E!%/E%0m]:&!DIV!&Set /P "FN=$E #: "&For %%v in ("!FN!")do (If /I "!FN!"=="Exit" (Exit /B 0)Else If /I "!FN!"=="E" (Exit /B 0)Else If "!FN!"==".." (CD .. &!DIV!&Echo/!CD!&!DIV!&Exit /B)Else If not "!$E[%%~v]!"=="" (Set "$E=!$E[%%~v]!"&!DIV!&Echo/!$E[%%~v]! Selected)Else (Echo/invalid index&!DIV!& Timeout 1 /Nobreak > Nul & Goto :Dir ))"
 Set "Do=Set "FN="&If /I "!Option!"=="Exit" (Goto :Eof)Else IF /I "!Option!"=="Ren" (For %%P in ("!Path[$E]!")Do (Set /P "FN=New Name: " & If "!FN!"=="" (!DIV!%/E%31mFilename required%/E%0m&!DIV!& Goto :!rLabel!)Else If Not exist "!FN!.$E" (Ren %%~nxP !FN!.$E)Else (!DIV!&Echo/%/E%31m"!FN!.$E" Already exists.%/E%0m&!DIV! & Goto :!rLabel!)) & !DIV!&Echo/%/E%32mRename Succesful.%/E%0m&!DIV! & Goto :!rLabel!)Else IF /I "!Option!"=="View Info" (Echo/Modified:!TAB!!TAB!Size:!TAB!Attribs:!TAB!Location:&!DIV! & For %%I in ("!Path[$E]!")Do (Echo/%%~tI!TAB!%%~zI!TAB!%%~aI!TAB!%%~dpI))Else (For %%i in ("!Path[$E]!")Do IF /I Not "!Option!"=="View Info" Echo/[!Option!] !Path[$E]!&!DIV!&!Option! "%%~i")"
 Set "Wait= Echo/&!DIV!&For %%n in (1 2) Do If %%n==2 (Set "$S=Str"& Call :ColorMenu $S & Echo/!$S!&!DIV! & Timeout !TO! > Nul 2> Nul )Else Set TO="
 Setlocal EnableDelayedExpansion
 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!-"
 Set "DIV=Echo/%/E%33m!DIV!%/E%0m"
 If exist "%userprofile%Desktop" (Set "SourceDir=%userprofile%Desktop") Else (Set "SourceDir=%~dp0")
 PUSHD "%SourceDir%" && cls || (Echo/You lack write permission in %~dp0 & Exit /B 1)
%Wait:Str=[!CD!]%0
:menu
 Title %~n0
 %Menu% Exit "Dir Change" Batch Text Vbs Cls "All Files" "User specified command" "Attribs"
 If /I "!Option!"=="Exit" (POPD & Endlocal & Endlocal & Goto :Eof) Else If "!Option!"=="Cls" (Cls)Else Call :!Option! 2> Nul
 Set "#A=32"
 %Wait:Str=!CD!%0
 %DEL/array:$E=Bat% & %DEL/array:$E=Txt% & %DEL/array:$E=Vbs%
Goto :menu
:Dir Change
 %GetFolders:$E=DirPath%
 %SelectFolder:$E=DirPath%
  PUSHD "%DirPath%"
Exit /B
:Batch
 %SelectFile:$E=Bat%Batch
 (%Menu% "Exit /B" Type Call "Start """ "Ren" "Del /P" Notepad.exe "View Info" "User Specified Command") && If "!Option!"=="User Specified Command" ( Call :!Option! 2> Nul )Else %Do:$E=Bat%
 %Wait:Str=Continue %50
Goto :Batch
:Text
 %SelectFile:$E=Txt%Text
 (%Menu% "Exit /B" Type "Ren" "Del /P" Notepad.exe "View Info" "User Specified Command") && If "!Option!"=="User Specified Command" ( Call :!Option! 2> Nul )Else %Do:$E=Txt%
 %Wait:Str=Continue.%50
Goto :Text
:Vbs
 %SelectFile:$E=Vbs%Vbs
 (%Menu% "Exit /B" Type "Ren" "Del /P" "Start """ Notepad.exe "View Info" "User Specified Command") && If "!Option!"=="User Specified Command" ( Call :!Option! 2> Nul )Else %Do:$E=Vbs%
 %Wait:Str=Continue.%50
Goto :Vbs
:All Files
Set "Spacer=                                                  "
 Echo/%/E%4m%/E%32mModified:%TAB%%TAB%%/E%90mSize:%TAB%%TAB%%/E%31mAtrribs:%TAB%%/E%34mType:%TAB%%/E%36mName:%/E%0m&Echo/
For /F "Delims=" %%G in ('Dir /B *.* /O:-D /T:W /A:-D') Do (
 SETLOCAL DISABLEdelayedExpansion
 Set "T=%%~tG" & Set "S=%%~zG%Spacer%" & Set "A=%%~aG%Spacer%" & Set "X=%%~xG%Spacer%" & Set "N=%%~nG"
 SETLOCAL ENABLEdelayedExpansion
 <Nul Set /P"=%/E%32m!T:~0,20!!TAB!%/E%90m!S:~0,12!!TAB!%/E%31m!A:~0,14!!TAB!%/E%34m!X:~0,5!!TAB!%/E%36m!N!%/E%0m"&Echo/
 ENDLOCAL
 ENDLOCAL
)
Goto :Eof
:Attribs
If Not Exist "!Path[%Ext%]!" (Echo/["!Path[%Ext%]!"] File selected does not exist & Exit /B 0)
!DIV!&Echo/%/E%32m !Path[%Ext%]!&!DIV!
%Menu%  "Exit /B" "Attrib -R" "Attrib +R" "Attrib -H" "Attrib +H"
if /I Not "!Option!"=="Exit /B" (%Option% "!Path[%Ext%]!" && For %%G in ("!Path[%Ext%]!")Do Echo/%%~aG)Else Exit /B 0
Goto :Attribs
:User specified command
Setlocal DISABLEdelayedexpansion
Set "CM="&amp

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...