'Batch list folder contents, then echo results as options to be set as variables
I usually like to try to work these out myself, but at the moment I have to admit I don't know where to start with this one. Hoping someone could kindly steer me in the right direction at least.
I have a folder with a number of .txt files
Text1.txt
Text2.txt
Text3.txt
In my windows bat file I need to list the contents of said folder and set them as options to be set as variables. example:
cls
echo[
echo[ Please select an option
echo[
echo (1) Text1
echo (2) Text2
echo (3) Text3
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=Text1
if !option!==2 set var=Text2
if !option!==3 set var=Text3
Any advice is greatly appreciated, this forum has been great.
*Edit here is something I tried
cls
echo[
echo[ Please select an option
echo[
dir /b "*.txt"
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=text1
if !option!==2 set var=text2
if !option!==3 set var=text3
it works, but does not add the numbers (1) before the options, and it also has them aligned left not centred.
Please select an option
text1.txt
text2.txt
text3.txt
Type your selection (1-3) and press ENTER=
Solution 1:[1]
There are different solutions you can build, here are 2 examples.
If you have only a few files you can utilize choice:
@echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
)
choice /c %cnt% /m "Choose"
echo you chose !fchoice%errorlevel%!
if you have many files though, choice might not be a viable option, then revert to set /p:
@echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
set "fin=%%i"
)
set /p "chosen=Select a file by number: "
for /l %%i in (1,1,%fin%) do if "%chosen%" == "%%i" set "check=1"
if not defined check echo Incorrect choice selected & goto :EOF
echo you chose !fchoice%chosen%!
Solution 2:[2]
Well, if this were any other language what would you do? Probably populate an array with your directory listing, right? Then use that array to pair menu option with file choice? Well, don't let the fact that the Batch language doesn't have arrays stop you. They're easy enough to simulate.
@echo off & setlocal
rem // init array index
set file.length=0
rem // for each .txt file in the current directory
for %%I in (*.txt) do (
rem // It's good practice only to enable delayed expansion when needed, as
rem // otherwise it can mangle values containing exclamation marks
setlocal enabledelayedexpansion
rem // use a "for /f" command to endlocal while reading the value of
rem // !file.length!. This preserves exclamation marks in file names.
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
rem // set /a doesn't require delayed expansion. It just works.
set /a file.ubound = file.length, file.length += 1
)
rem // Display the collection of variables named file...something.
set file
There you go. The last line should show you a list of all the variables beginning with file, including the simulated .length and .ubound properties. From there, just use a for /L %%I in (0, 1, %file.ubound%) to display your menu.
Here's a bit more. Firstly, I read your comment explaining that the number of txt files could exceed 50. By default, the Windows cmd console is 24 lines. Wouldn't it be nice to columnify the output so the user doesn't have to scroll? I wrote a utility script that will take a flat list and columnify it based on the number of rows in the current cmd console. Save this as...
columnify.bat:
@if (@CodeSection == @Batch) @then
@echo off & setlocal
if "%~1"=="test" (
rem // this errors if there's redirected input buffer waiting
timeout /t 0 /nobreak >NUL 2>NUL && (
echo Usage: command list output ^| %~nx0
echo or %~nx0 ^< txtfile containing a list
echo;
echo Hit Ctrl-C to exit.
)
exit
)
for /f "usebackq tokens=1,2 delims=," %%I in (
`powershell "(Get-Host).UI.RawUI.WindowSize.toString()"`
) do (
rem // detect whether input buffer has content waiting
start /b cmd /c "%~f0" test
cscript /nologo /e:JScript "%~f0" %%I %%J
)
goto :EOF
@end // end Batch / begin JScript hybrid code
var stdin = WSH.CreateObject('Scripting.FileSystemObject').GetStandardStream(0).ReadAll();
cols = WSH.Arguments(0) * 1 - 1,
rows = WSH.Arguments(1) * 1 - 4;
var out = stdin.split(/\r?\n/), buffer = [], maxlen, col = 0;
if (rows > out.length) { rows = out.length; }
while (out.length) {
buffer[col] = [];
maxlen = 0;
while (buffer[col].length < rows) {
val = out.length ? out.shift() : '';
buffer[col].push(val);
if (maxlen < val.length) maxlen = val.length;
}
for (var i = buffer[col].length; i--;) {
while (buffer[col][i].length < maxlen) { buffer[col][i] += ' '; }
}
col++;
}
for (var i=0; i < buffer[0].length; i++) {
var line = [];
for (var j=0; j < col; j++) {
line.push(buffer[j][i]);
}
WSH.Echo(line.join(' ').substr(0, cols));
}
Now your main script can make use of columnify.bat by piping output through it.
@echo off & setlocal
rem // All the same stuff as above, but without the comments.
set file.length=0
for %%I in (*.txt) do (
setlocal enabledelayedexpansion
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
set /a file.ubound = file.length, file.length += 1
)
cls
:displaymenu
echo Always press your luck. Which file do you choose?
echo;
( for /L %%I in (0,1,%file.ubound%) do @(
call echo %%I: %%file[%%~I]%%
) ) | columnify
echo;
set /P "choice=Enter a number: "
if %choice% GEQ 0 if %choice% LEQ %file.ubound% (
setlocal enabledelayedexpansion
echo You chose !file[%choice%]!. Neat.
endlocal
) else (
cls
powershell "write-host -f red 'Invalid response. Enter a number between 0 and %file.ubound%.'"
goto displaymenu
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
